From 8a0dced7d9344b92ae6053554051e85a1e5208c7 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Tue, 26 Nov 2024 15:00:33 -0800 Subject: [PATCH] Add `async_gen()` (async version of `gen()`) --- NAMESPACE | 1 + R/async.R | 25 +++++++++++++++++++++++-- man/async_generator.Rd | 19 ++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 9939ed9..15a6bd5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,6 +9,7 @@ S3method(print,coro_generator_instance) export(as_iterator) export(async) export(async_collect) +export(async_gen) export(async_generator) export(async_ops) export(async_sleep) diff --git a/R/async.R b/R/async.R index b827d03..b58c61d 100644 --- a/R/async.R +++ b/R/async.R @@ -76,7 +76,7 @@ await <- function(x) { #' @export async_sleep <- function(seconds) { promises::promise(function(resolve, reject) { - later::later(~ resolve(NULL) , delay = seconds) + later::later(~ resolve(NULL), delay = seconds) }) } @@ -116,13 +116,34 @@ async_sleep <- function(seconds) { #' # Example usage: #' if (interactive()) { #' library(magrittr) -#' generate_stream(1:3) %>% async_map(`*`, 2) %>% async_collect() +#' generate_stream(1:3) %>% +#' async_map(`*`, 2) %>% +#' async_collect() +#' } +#' +#' # coro provides a short syntax `async_gen()` for creating one-off +#' # generator _instances_. It is handy to adapt existing iterators: +#' numbers <- generate_stream(1:10) +#' odds <- async_gen(for (x in await_each(numbers)) if (x %% 2 != 0) yield(x)) +#' squares <- async_gen(for (x in await_each(odds)) yield(x^2)) +#' greetings <- async_gen(for (x in await_each(squares)) yield(paste("Hey", x))) +#' if (interactive()) { +#' async_collect(greetings) %>% promises::then(print) #' } #' @export async_generator <- function(fn) { assert_lambda(substitute(fn)) generator0(fn, type = "async_generator") } + +#' @rdname async_generator +#' @param expr A yielding expression. +#' @export +async_gen <- function(expr) { + fn <- new_function(NULL, substitute(expr), caller_env()) + generator0(fn, type = "async_generator")() +} + #' @rdname async_generator #' @inheritParams await #' @export diff --git a/man/async_generator.Rd b/man/async_generator.Rd index 9c3a2c0..1fa7608 100644 --- a/man/async_generator.Rd +++ b/man/async_generator.Rd @@ -2,17 +2,22 @@ % Please edit documentation in R/async.R \name{async_generator} \alias{async_generator} +\alias{async_gen} \alias{await_each} \title{Construct an async generator} \usage{ async_generator(fn) +async_gen(expr) + await_each(x) } \arguments{ \item{fn}{An anonymous function describing an async generator within which \code{await()} calls are allowed.} +\item{expr}{A yielding expression.} + \item{x}{An awaitable value, i.e. a \link[promises:promise]{promise}.} } \value{ @@ -44,7 +49,19 @@ async_map <- async_generator(function(.i, .fn, ...) { # Example usage: if (interactive()) { library(magrittr) - generate_stream(1:3) \%>\% async_map(`*`, 2) \%>\% async_collect() + generate_stream(1:3) \%>\% + async_map(`*`, 2) \%>\% + async_collect() +} + +# coro provides a short syntax `async_gen()` for creating one-off +# generator _instances_. It is handy to adapt existing iterators: +numbers <- generate_stream(1:10) +odds <- async_gen(for (x in await_each(numbers)) if (x \%\% 2 != 0) yield(x)) +squares <- async_gen(for (x in await_each(odds)) yield(x^2)) +greetings <- async_gen(for (x in await_each(squares)) yield(paste("Hey", x))) +if (interactive()) { + async_collect(greetings) \%>\% promises::then(print) } } \seealso{