coro icon indicating copy to clipboard operation
coro copied to clipboard

programmatic async function creation

Open ElianHugh opened this issue 1 year ago • 3 comments

It would be nice to programmatically create an async function, such as when you want to convert an expression into an anonymous function.

An example interface could be:

as_async_function(
    { await(foo) }
)

At the moment we can only pass anonymous functions to coro::async because of the substitute call in coro::: assert_lambda. Technically I could use coro:::generator0(fn, type = "async"), but it seems it's not exported for a reason.

You can get half of the way with rlang::inject, but it's a bit hacky and you can't use it to set the formals of the anonymous function.

ElianHugh avatar Jan 18 '24 05:01 ElianHugh

inject() is a valid approach to metaprogramming. But I wonder, from what information would you generate the formals? I think you're looking for the equivalent of rlang::new_function() where you'd pass formals, env, and body individually?

lionel- avatar Jan 18 '24 07:01 lionel-

Right, I was looking exactly for something analogous to rlang::new_function. I was trying to modify the formals via formals but that seems to not work as expected, and also drops the aync function class

As an aside, I don't mean to suggest inject is hacky, more that it feels like a workaround. Technically I can create an anonymous function through rlang::new_function, but that will end up as a name when passed to assert_lambda

ElianHugh avatar Jan 18 '24 11:01 ElianHugh

The tricky part is that async() takes calls to function instead of evaluated functions.

These calls are a bit tricky, see as.list(quote(function(foo) bar)) for the contents. The second element is a pairlist not a list. If you create a call following this structure (e.g. turn the result of the previous example back to a call with as.call()), then you can inject it inside async().

I agree a new_ function would be much better.

lionel- avatar Jan 18 '24 13:01 lionel-