r-lib / coro

Coroutines for R
https://coro.r-lib.org/
Other
159 stars 8 forks source link

programmatic async function creation #43

Open ElianHugh opened 9 months ago

ElianHugh commented 9 months ago

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.

lionel- commented 9 months ago

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?

ElianHugh commented 9 months ago

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

lionel- commented 9 months ago

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.