-
+
+
@@ -127,6 +135,17 @@
Once an iterator has signalled exhaustion, all subsequent
invokations must consistently return coro::exhausted()
or
as.symbol(".__exhausted__.")
.
+The iterator function may have a close
argument taking boolean
+values. When passed a TRUE
value, it indicates early termination
+and the iterator is given the opportunity to clean up resources.
+Cleanup must only be performed once, even if the iterator is called
+multiple times with close = TRUE
.
+An iterator is allowed to not have any close
argument. Iterator
+drivers must check for the presence of the argument. If not present,
+the iterator can be dropped without cleanup.
+An iterator passed close = TRUE
must return coro::exhausted()
and
+once closed, an iterator must return coro::exhausted()
when called
+again.
diff --git a/reference/loop.html b/reference/loop.html
new file mode 100644
index 0000000..c75dead
--- /dev/null
+++ b/reference/loop.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/reference/yield.html b/reference/yield.html
index 0cbc41d..63570b5 100644
--- a/reference/yield.html
+++ b/reference/yield.html
@@ -1,5 +1,5 @@
-
Yield a value from a generator — yield • coroYield a value from a generator — yield • coro
+">
Skip to content
-
-
diff --git a/search.json b/search.json
index b247a4d..a5c10b8 100644
--- a/search.json
+++ b/search.json
@@ -1 +1 @@
-[{"path":[]},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"our-pledge","dir":"","previous_headings":"","what":"Our Pledge","title":"Contributor Covenant Code of Conduct","text":"members, contributors, leaders pledge make participation community harassment-free experience everyone, regardless age, body size, visible invisible disability, ethnicity, sex characteristics, gender identity expression, level experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, sexual identity orientation. pledge act interact ways contribute open, welcoming, diverse, inclusive, healthy community.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"our-standards","dir":"","previous_headings":"","what":"Our Standards","title":"Contributor Covenant Code of Conduct","text":"Examples behavior contributes positive environment community include: Demonstrating empathy kindness toward people respectful differing opinions, viewpoints, experiences Giving gracefully accepting constructive feedback Accepting responsibility apologizing affected mistakes, learning experience Focusing best just us individuals, overall community Examples unacceptable behavior include: use sexualized language imagery, sexual attention advances kind Trolling, insulting derogatory comments, personal political attacks Public private harassment Publishing others’ private information, physical email address, without explicit permission conduct reasonably considered inappropriate professional setting","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"enforcement-responsibilities","dir":"","previous_headings":"","what":"Enforcement Responsibilities","title":"Contributor Covenant Code of Conduct","text":"Community leaders responsible clarifying enforcing standards acceptable behavior take appropriate fair corrective action response behavior deem inappropriate, threatening, offensive, harmful. Community leaders right responsibility remove, edit, reject comments, commits, code, wiki edits, issues, contributions aligned Code Conduct, communicate reasons moderation decisions appropriate.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"scope","dir":"","previous_headings":"","what":"Scope","title":"Contributor Covenant Code of Conduct","text":"Code Conduct applies within community spaces, also applies individual officially representing community public spaces. Examples representing community include using official e-mail address, posting via official social media account, acting appointed representative online offline event.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"enforcement","dir":"","previous_headings":"","what":"Enforcement","title":"Contributor Covenant Code of Conduct","text":"Instances abusive, harassing, otherwise unacceptable behavior may reported community leaders responsible enforcement codeofconduct@posit.co. complaints reviewed investigated promptly fairly. community leaders obligated respect privacy security reporter incident.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"enforcement-guidelines","dir":"","previous_headings":"","what":"Enforcement Guidelines","title":"Contributor Covenant Code of Conduct","text":"Community leaders follow Community Impact Guidelines determining consequences action deem violation Code Conduct:","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_1-correction","dir":"","previous_headings":"Enforcement Guidelines","what":"1. Correction","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Use inappropriate language behavior deemed unprofessional unwelcome community. Consequence: private, written warning community leaders, providing clarity around nature violation explanation behavior inappropriate. public apology may requested.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_2-warning","dir":"","previous_headings":"Enforcement Guidelines","what":"2. Warning","title":"Contributor Covenant Code of Conduct","text":"Community Impact: violation single incident series actions. Consequence: warning consequences continued behavior. interaction people involved, including unsolicited interaction enforcing Code Conduct, specified period time. includes avoiding interactions community spaces well external channels like social media. Violating terms may lead temporary permanent ban.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_3-temporary-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"3. Temporary Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: serious violation community standards, including sustained inappropriate behavior. Consequence: temporary ban sort interaction public communication community specified period time. public private interaction people involved, including unsolicited interaction enforcing Code Conduct, allowed period. Violating terms may lead permanent ban.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_4-permanent-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"4. Permanent Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Demonstrating pattern violation community standards, including sustained inappropriate behavior, harassment individual, aggression toward disparagement classes individuals. Consequence: permanent ban sort public interaction within community.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"attribution","dir":"","previous_headings":"","what":"Attribution","title":"Contributor Covenant Code of Conduct","text":"Code Conduct adapted Contributor Covenant, version 2.1, available https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. Community Impact Guidelines inspired [Mozilla’s code conduct enforcement ladder][https://github.com/mozilla/inclusion]. answers common questions code conduct, see FAQ https://www.contributor-covenant.org/faq. Translations available https://www.contributor-covenant.org/translations.","code":""},{"path":"https://coro.r-lib.org/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"MIT License","title":"MIT License","text":"Copyright (c) 2020 coro authors Permission hereby granted, free charge, person obtaining copy software associated documentation files (“Software”), deal Software without restriction, including without limitation rights use, copy, modify, merge, publish, distribute, sublicense, /sell copies Software, permit persons Software furnished , subject following conditions: copyright notice permission notice shall included copies substantial portions Software. SOFTWARE PROVIDED “”, WITHOUT WARRANTY KIND, EXPRESS IMPLIED, INCLUDING LIMITED WARRANTIES MERCHANTABILITY, FITNESS PARTICULAR PURPOSE NONINFRINGEMENT. EVENT SHALL AUTHORS COPYRIGHT HOLDERS LIABLE CLAIM, DAMAGES LIABILITY, WHETHER ACTION CONTRACT, TORT OTHERWISE, ARISING , CONNECTION SOFTWARE USE DEALINGS SOFTWARE.","code":""},{"path":"https://coro.r-lib.org/articles/generator.html","id":"iterators","dir":"Articles","previous_headings":"","what":"Iterators","title":"Generators","text":"Generators simple way creating iterator functions, .e. functions can call return new value. iteration protocol described ?iterator. simple iterator iterates elements 1:3: iterator exhausted, returns sentinel value signals caller values available: R normally don’t use sort iteration work vectors. Instead, use idiomatic techniques vectorised programming. Iterator functions useful specific tasks: Iterating chunks data whole data doesn’t fit memory. Generating sequences don’t know advance many elements need. sequences may complex even infinite. iterator protocol designed free dependency. However, easiest way create iterator using generator factories provided package.","code":"library(coro) iterator <- as_iterator(1:3) # Call the iterator to retrieve new values iterator() #> [1] 1 iterator() #> [1] 2 # This is the last value iterator() #> [1] 3 # This is the exhaustion sentinel iterator() #> .__exhausted__."},{"path":"https://coro.r-lib.org/articles/generator.html","id":"generators","dir":"Articles","previous_headings":"","what":"Generators","title":"Generators","text":"Generators create functions can yield, .e. suspend . generator reaches yield(value) statement returns value called return(value). However, calling generator resumes function right left . preserve state invokations, generators ideal creating iterator functions. generator() creates iterator factory. function returns fresh iterator functions: last loop generator finished iterating (one), returns exhaustion sentinel: can also create infinite iterators can’t exhausted:","code":"generate_abc <- generator(function() { for (x in letters[1:3]) { yield(x) } }) # Create the iterator abc <- generate_abc() # Use the iterator by invoking it abc() #> [1] \"a\" abc() #> [1] \"b\" # Last value abc() #> [1] \"c\" # Exhaustion sentinel abc() #> .__exhausted__. abc() #> .__exhausted__. generate_natural_numbers <- generator(function(from = 1L) { x <- from repeat { yield(x) x <- x + 1L } }) natural_numbers <- generate_natural_numbers(from = 10L) # The iterator generates new numbers forever natural_numbers() #> [1] 10 natural_numbers() #> [1] 11"},{"path":"https://coro.r-lib.org/articles/generator.html","id":"iterating","dir":"Articles","previous_headings":"","what":"Iterating","title":"Generators","text":"Iterating manually iterator function bit tricky watch exhaustion sentinel: simpler way iterate loop using iterate() helper. Within iterate(), understands iterator protocol: can also collect remaning values iterator list collect(): Beware trying exhaust infinite iterator programming error. causes infinite loop never returns, forcing user interrupt R ctrl-c. Make sure iterate infinite iterator finite amount time:","code":"abc <- generate_abc() while (!is_exhausted(x <- abc())) { print(x) } #> [1] \"a\" #> [1] \"b\" #> [1] \"c\" abc <- generate_abc() loop(for (x in abc) { print(x) }) #> [1] \"a\" #> [1] \"b\" #> [1] \"c\" abc <- generate_abc() collect(abc) #> [[1]] #> [1] \"a\" #> #> [[2]] #> [1] \"b\" #> #> [[3]] #> [1] \"c\" for (x in 1:3) { print(natural_numbers()) } #> [1] 12 #> [1] 13 #> [1] 14 collect(natural_numbers, n = 3) #> [[1]] #> [1] 15 #> #> [[2]] #> [1] 16 #> #> [[3]] #> [1] 17"},{"path":"https://coro.r-lib.org/articles/generator.html","id":"adapting-generators","dir":"Articles","previous_headings":"","what":"Adapting generators","title":"Generators","text":"generator factory can take another iterator argument modify values. pattern called adapting: modified iterator exhausted, adaptor automatically closes well: user, might want create iterator factory one-adaptor. case can use gen() instead generator(). enables pythonic style working iterators: can use general purpose adaptor adapt_map(). maps function value iterator:","code":"library(magrittr) adapt_toupper <- generator(function(i) { for (x in i) { yield(toupper(x)) } }) ABC <- generate_abc() %>% adapt_toupper() ABC() #> [1] \"A\" ABC() #> [1] \"B\" ABC() #> [1] \"C\" ABC() #> .__exhausted__. abc <- generate_abc() ABC <- gen(for (x in abc) yield(toupper(x))) collect(ABC) #> [[1]] #> [1] \"A\" #> #> [[2]] #> [1] \"B\" #> #> [[3]] #> [1] \"C\" adapt_map <- generator(function(.i, .fn, ...) { for (x in .i) { yield(.fn(x, ...)) } }) ABC <- generate_abc() %>% adapt_map(toupper) ABC() #> [1] \"A\""},{"path":"https://coro.r-lib.org/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Lionel Henry. Author, maintainer. . Copyright holder, funder.","code":""},{"path":"https://coro.r-lib.org/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Henry L (2024). coro: 'Coroutines' R. R package version 1.0.4, https://github.com/r-lib/coro.","code":"@Manual{, title = {coro: 'Coroutines' for R}, author = {Lionel Henry}, year = {2024}, note = {R package version 1.0.4}, url = {https://github.com/r-lib/coro}, }"},{"path":[]},{"path":"https://coro.r-lib.org/index.html","id":"overview","dir":"","previous_headings":"","what":"Overview","title":"Coroutines for R","text":"coro implements coroutines R, .e. functions can suspended resumed later . two kinds: Async functions, make straightforward program concurrently Generators iterating complex sequences Supported features: Suspending within loops /else branches Suspending within tryCatch() .exit() expressions stack-based cleanup provided local_ functions withr package Step-debugging browser() within coroutines Compatibility : Python iterators reticulate package Async operations promises package Parallel computations future package Attach package follow examples:","code":"library(coro)"},{"path":"https://coro.r-lib.org/index.html","id":"asyncawait-functions","dir":"","previous_headings":"Overview","what":"Async/await functions","title":"Coroutines for R","text":"Concurrent programming made straightforward async-await functions. Whenever waiting result may take (downloading file, computing value external process), use await(). argument await() must return promise promises package. Concurrent code based promises can quickly become hard write follow. following artificial example, wait download complete, decide launch computation external process depending property downloaded data. also handle errors specifically. Rewriting function async/await greatly simplifies code:","code":"my_async <- function() { async_download() %>% then(function(data) { if (ncol(data) > 10) { then(future::future(fib(30)), function(fib) { data / fib }) } else { data } }, onRejected = function(err) { if (inherits(err, \"download_error\")) { NULL } else { stop(err) } }) } my_async <- async(function() { data <- tryCatch( await(async_download()), download_error = function(err) NULL ) if (is.null(data)) { return(NULL) } if (ncol(data) > 10) { fib <- await(future::future(fib(30))) data <- data /fib } data })"},{"path":"https://coro.r-lib.org/index.html","id":"generators","dir":"","previous_headings":"Overview","what":"Generators","title":"Coroutines for R","text":"Generators based simple iteration protocol: Iterators functions. can advanced calling function. new value returned. exhausted iterator returns sentinel symbol exhausted. generator() function creates generator factory returns generator instances: generator instance iterator function yields values: Collect remaining values iterator collect(): Iterate iterator loop(): See vignette(\"generator\") information.","code":"# Create a generator factory generate_abc <- generator(function() { for (x in letters[1:3]) { yield(x) } }) # Create a generator instance abc <- generate_abc() abc #>
#> function() { #> for (x in letters[1:3]) { #> yield(x) #> } #> } abc() #> [1] \"a\" collect(abc) #> [[1]] #> [1] \"b\" #> #> [[2]] #> [1] \"c\" loop(for (x in generate_abc()) { print(toupper(x)) }) #> [1] \"A\" #> [1] \"B\" #> [1] \"C\""},{"path":"https://coro.r-lib.org/index.html","id":"compatibility-with-the-reticulate-package","dir":"","previous_headings":"Overview","what":"Compatibility with the reticulate package","title":"Coroutines for R","text":"Python iterators imported reticulate package compatible loop() collect(): can also composed coro generators:","code":"suppressMessages(library(reticulate)) py_run_string(\" def first_n(n): num = 1 while num <= n: yield num num += 1 \") loop(for (x in py$first_n(3)) { print(x * 2) }) #> [1] 2 #> [1] 4 #> [1] 6 times <- generator(function(it, n) for (x in it) yield(x * n)) composed <- times(py$first_n(3), 10) collect(composed) #> [[1]] #> [1] 10 #> #> [[2]] #> [1] 20 #> #> [[3]] #> [1] 30"},{"path":"https://coro.r-lib.org/index.html","id":"limitations","dir":"","previous_headings":"","what":"Limitations","title":"Coroutines for R","text":"yield() await() can used loops, /else branches, tryCatch() expressions, combinations . However can’t used function arguments. cause errors: Fortunately easy rewrite code work around limitation:","code":"generator(function() { list(yield(\"foo\")) }) async(function() { list(await(foo())) }) generator(function() { x <- yield(\"foo\") list(x) }) async(function() { x <- await(foo()) list(x) })"},{"path":"https://coro.r-lib.org/index.html","id":"how-does-it-work","dir":"","previous_headings":"","what":"How does it work","title":"Coroutines for R","text":"Coroutines abstraction state machines languages support . Conversely, can implement coroutines rewriting code source provided user state machine. Pass internals = TRUE print methods coroutines reveal state machine running hood: Despite transformation source code, browser() step-debugging still work expect. coro keeps track source references original code.","code":"print(generate_abc, internals = TRUE) #> #> function() { #> for (x in letters[1:3]) { #> yield(x) #> } #> } #> State machine: #> { #> if (exhausted) { #> return(invisible(exhausted())) #> } #> repeat switch(state[[1L]], `1` = { #> iterators[[2L]] <- as_iterator(user(letters[1:3])) #> state[[1L]] <- 2L #> state[[2L]] <- 1L #> }, `2` = { #> repeat switch(state[[2L]], `1` = { #> if ({ #> iterator <- iterators[[2L]] #> if (is_exhausted(elt <- iterator())) { #> FALSE #> } else { #> user_env[[\"x\"]] <- elt #> TRUE #> } #> }) { #> state[[2L]] <- 2L #> } else { #> break #> } #> }, `2` = { #> user({ #> x #> }) #> state[[2L]] <- 3L #> suspend() #> return(last_value()) #> }, `3` = { #> .last_value <- if (missing(arg)) NULL else arg #> state[[2L]] <- 1L #> }) #> iterators[[2L]] <- NULL #> length(state) <- 1L #> break #> }) #> exhausted <- TRUE #> invisible(exhausted()) #> }"},{"path":"https://coro.r-lib.org/index.html","id":"acknowledgements","dir":"","previous_headings":"","what":"Acknowledgements","title":"Coroutines for R","text":"regenerator Javascript package uses similar transformation implement generators async functions older versions Javascript. Gabor Csardi many interesting discussions concurrency design coro.","code":""},{"path":"https://coro.r-lib.org/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Coroutines for R","text":"Install development version github :","code":"# install.packages(\"devtools\") devtools::install_github(\"r-lib/coro\", build_vignettes = TRUE)"},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":null,"dir":"Reference","previous_headings":"","what":"Transform an object to an iterator — as_iterator","title":"Transform an object to an iterator — as_iterator","text":"as_iterator() generic function transforms input iterator function. default implementation follows: Functions returned . objects assumed vectors length() [[ methods. Methods must return functions implement coro's iterator protocol. as_iterator() called coro RHS loops. applies within generators, async functions, loop().","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Transform an object to an iterator — as_iterator","text":"","code":"as_iterator(x) # S3 method for default as_iterator(x)"},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Transform an object to an iterator — as_iterator","text":"x object.","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Transform an object to an iterator — as_iterator","text":"iterable function.","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Transform an object to an iterator — as_iterator","text":"","code":"as_iterator(1:3) #> function () #> { #> if (i == n) { #> return(exhausted()) #> } #> i <<- i + 1L #> x[[i]] #> } #> #> i <- as_iterator(1:3) loop(for (x in i) print(x)) #> [1] 1 #> [1] 2 #> [1] 3"},{"path":"https://coro.r-lib.org/reference/async.html","id":null,"dir":"Reference","previous_headings":"","what":"Make an async function — async","title":"Make an async function — async","text":"async() functions building blocks cooperative concurrency. concurrent jointly managed scheduler charge running . cooperative decide can longer make quick progress need await result. done await() keyword suspends async function gives control back scheduler. scheduler waits next async operation ready make progress. async framework used async() functions implemented later promises packages: can chain async functions created coro promises. can await promises. can also await futures created future package coercible promises.","code":""},{"path":"https://coro.r-lib.org/reference/async.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Make an async function — async","text":"","code":"async(fn) await(x)"},{"path":"https://coro.r-lib.org/reference/async.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Make an async function — async","text":"fn anonymous function within await() calls allowed. x awaitable value, .e. promise.","code":""},{"path":"https://coro.r-lib.org/reference/async.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Make an async function — async","text":"function returns promises::promise().","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/async.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Make an async function — async","text":"","code":"# This async function counts down from `n`, sleeping for 2 seconds # at each iteration: async_count_down <- async(function(n) { while (n > 0) { cat(\"Down\", n, \"\\n\") await(async_sleep(2)) n <- n - 1 } }) # This async function counts up until `stop`, sleeping for 0.5 # seconds at each iteration: async_count_up <- async(function(stop) { n <- 1 while (n <= stop) { cat(\"Up\", n, \"\\n\") await(async_sleep(0.5)) n <- n + 1 } }) # You can run these functions concurrently using `promise_all()` if (interactive()) { promises::promise_all(async_count_down(5), async_count_up(5)) }"},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":null,"dir":"Reference","previous_headings":"","what":"Collect elements of an asynchronous iterator — async_collect","title":"Collect elements of an asynchronous iterator — async_collect","text":"async_collect() takes asynchronous iterator, .e. iterable function also awaitable. async_collect() returns awaitable eventually resolves list containing values returned iterator. values collected exhaustion unless n supplied. collection grown geometrically performance.","code":""},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Collect elements of an asynchronous iterator — async_collect","text":"","code":"async_collect(x, n = NULL)"},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Collect elements of an asynchronous iterator — async_collect","text":"x iterator function. n number elements collect. x infinite sequence, n must supplied prevent infinite loop.","code":""},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Collect elements of an asynchronous iterator — async_collect","text":"","code":"# Emulate an async stream by yielding promises that resolve to the # elements of the input vector generate_stream <- async_generator(function(x) for (elt in x) yield(elt)) # You can await `async_collect()` in an async function. Once the # list of values is resolved, the async function resumes. async(function() { stream <- generate_stream(1:3) values <- await(async_collect(stream)) values }) #> #> function() { #> stream <- generate_stream(1:3) #> values <- await(async_collect(stream)) #> values #> } #> "},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":null,"dir":"Reference","previous_headings":"","what":"Construct an async generator — async_generator","title":"Construct an async generator — async_generator","text":"async generator constructs iterable functions also awaitables. support yield() await() syntax. async iterator can looped within async functions iterators using await_each() input loop. iteration protocol derived one described iterator. async iterator always returns promise. iterator exhausted, returns resolved promise exhaustion sentinel.","code":""},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Construct an async generator — async_generator","text":"","code":"async_generator(fn) await_each(x)"},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Construct an async generator — async_generator","text":"fn anonymous function describing async generator within await() calls allowed. x awaitable value, .e. promise.","code":""},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Construct an async generator — async_generator","text":"generator factory. Generators constructed factory always return promises::promise().","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Construct an async generator — async_generator","text":"","code":"# Creates awaitable functions that transform their inputs into a stream generate_stream <- async_generator(function(x) for (elt in x) yield(elt)) # Maps a function to a stream async_map <- async_generator(function(.i, .fn, ...) { for (elt in await_each(.i)) { yield(.fn(elt, ...)) } }) # Example usage: if (interactive()) { library(magrittr) generate_stream(1:3) %>% async_map(`*`, 2) %>% async_collect() }"},{"path":"https://coro.r-lib.org/reference/async_ops.html","id":null,"dir":"Reference","previous_headings":"","what":"Async operations — async_ops","title":"Async operations — async_ops","text":"Customisation point async package concurrency framework defines \"\" operation. Assign result async_ops() .__coro_async_ops__. symbol namespace.","code":""},{"path":"https://coro.r-lib.org/reference/async_ops.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Async operations — async_ops","text":"","code":"async_ops(package, then, as_promise)"},{"path":"https://coro.r-lib.org/reference/async_ops.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Async operations — async_ops","text":"package package name framework string. async() async_generator() check package installed runtime. function two arguments. first argument promise object (created as_promise). second argument callback function must called promise object resolved. as_promise function one argument. -op passed promise object, otherwise wrap value resolved promise.","code":""},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":null,"dir":"Reference","previous_headings":"","what":"Sleep asynchronously — async_sleep","title":"Sleep asynchronously — async_sleep","text":"Sleep asynchronously","code":""},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Sleep asynchronously — async_sleep","text":"","code":"async_sleep(seconds)"},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Sleep asynchronously — async_sleep","text":"seconds number second sleep.","code":""},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Sleep asynchronously — async_sleep","text":"chainable promise.","code":""},{"path":"https://coro.r-lib.org/reference/collect.html","id":null,"dir":"Reference","previous_headings":"","what":"Iterate over iterator functions — collect","title":"Iterate over iterator functions — collect","text":"loop() collect() helpers iterating iterator functions generators. loop() takes loop expression collection can iterator function. collect() loops iterator collects values list.","code":""},{"path":"https://coro.r-lib.org/reference/collect.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Iterate over iterator functions — collect","text":"","code":"collect(x, n = NULL) loop(loop)"},{"path":"https://coro.r-lib.org/reference/collect.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Iterate over iterator functions — collect","text":"x iterator function. n number elements collect. x infinite sequence, n must supplied prevent infinite loop. loop loop expression.","code":""},{"path":"https://coro.r-lib.org/reference/collect.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Iterate over iterator functions — collect","text":"collect() returns list values; loop() returns exhausted() sentinel, invisibly.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/collect.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Iterate over iterator functions — collect","text":"","code":"generate_abc <- generator(function() for (x in letters[1:3]) yield(x)) abc <- generate_abc() # Collect 1 element: collect(abc, n = 1) #> [[1]] #> [1] \"a\" #> # Collect all remaining elements: collect(abc) #> [[1]] #> [1] \"b\" #> #> [[2]] #> [1] \"c\" #> # With exhausted iterators collect() returns an empty list: collect(abc) #> list() # With loop() you can use `for` loops with iterators: abc <- generate_abc() loop(for (x in abc) print(x)) #> [1] \"a\" #> [1] \"b\" #> [1] \"c\""},{"path":"https://coro.r-lib.org/reference/coro-package.html","id":null,"dir":"Reference","previous_headings":"","what":"coro: 'Coroutines' for R — coro-package","title":"coro: 'Coroutines' for R — coro-package","text":"Provides 'coroutines' R, family functions can suspended resumed later . includes 'async' functions (await) generators (yield). 'Async' functions based concurrency framework 'promises' package. Generators based dependency free iteration protocol defined 'coro' compatible iterators 'reticulate' package.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/coro-package.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"coro: 'Coroutines' for R — coro-package","text":"Maintainer: Lionel Henry lionel@posit.co contributors: Posit Software, PBC [copyright holder, funder]","code":""},{"path":"https://coro.r-lib.org/reference/coro_debug.html","id":null,"dir":"Reference","previous_headings":"","what":"Debug a generator or async function — coro_debug","title":"Debug a generator or async function — coro_debug","text":"Call coro_debug() generator(), async(), async_generator() function enable step-debugging. Alternatively, set options(coro_debug = TRUE) step-debugging functions created coro.","code":""},{"path":"https://coro.r-lib.org/reference/coro_debug.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Debug a generator or async function — coro_debug","text":"","code":"coro_debug(fn, value = TRUE)"},{"path":"https://coro.r-lib.org/reference/coro_debug.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Debug a generator or async function — coro_debug","text":"fn generator factory async function. value Whether debug function.","code":""},{"path":"https://coro.r-lib.org/reference/generator.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a generator function — generator","title":"Create a generator function — generator","text":"generator() creates generator factory. generator iterator function can pause execution yield() resume left . manage state , generators easiest way create iterators. See vignette(\"generator\"). following rules apply: Yielded values terminate generator. call generator , execution resumes right yielding point. local variables preserved. Returned values terminate generator. called return(), generator keeps returning exhausted() sentinel. Generators compatible features based iterator protocol loop() collect().","code":""},{"path":"https://coro.r-lib.org/reference/generator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a generator function — generator","text":"","code":"generator(fn) gen(expr)"},{"path":"https://coro.r-lib.org/reference/generator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a generator function — generator","text":"fn function template generators. function can yield() values. Within generator, loops iterator support. expr yielding expression.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/generator.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a generator function — generator","text":"","code":"# A generator statement creates a generator factory. The # following generator yields two times and then returns `\"c\"`: generate_abc <- generator(function() { yield(\"a\") yield(\"b\") \"c\" }) # Or equivalently: generate_abc <- generator(function() { for (x in letters[1:3]) { yield(x) } }) # The factory creates generator instances. They are iterators # that you can call successively to obtain new values: abc <- generate_abc() abc() #> [1] \"a\" abc() #> [1] \"b\" # Once a generator has returned it keeps returning `exhausted()`. # This signals to its caller that new values can no longer be # produced. The generator is exhausted: abc() #> [1] \"c\" abc() #> .__exhausted__. # You can only exhaust a generator once but you can always create # new ones from a factory: abc <- generate_abc() abc() #> [1] \"a\" # As generators implement the coro iteration protocol, you can use # coro tools like `loop()`. It makes it possible to loop over # iterators with `for` expressions: loop(for (x in abc) print(x)) #> [1] \"b\" #> [1] \"c\" # To gather values of an iterator in a list, use `collect()`. Pass # the `n` argument to collect that number of elements from a # generator: abc <- generate_abc() collect(abc, 1) #> [[1]] #> [1] \"a\" #> # Or drain all remaining elements: collect(abc) #> [[1]] #> [1] \"b\" #> #> [[2]] #> [1] \"c\" #> # coro provides a short syntax `gen()` for creating one-off # generator _instances_. It is handy to adapt existing iterators: numbers <- 1:10 odds <- gen(for (x in numbers) if (x %% 2 != 0) yield(x)) squares <- gen(for (x in odds) yield(x^2)) greetings <- gen(for (x in squares) yield(paste(\"Hey\", x))) collect(greetings) #> [[1]] #> [1] \"Hey 1\" #> #> [[2]] #> [1] \"Hey 9\" #> #> [[3]] #> [1] \"Hey 25\" #> #> [[4]] #> [1] \"Hey 49\" #> #> [[5]] #> [1] \"Hey 81\" #> # Arguments passed to generator instances are returned from the # `yield()` statement on reentry: new_tally <- generator(function() { count <- 0 while (TRUE) { i <- yield(count) count <- count + i } }) tally <- new_tally() tally(1) #> [1] 0 tally(2) #> [1] 2 tally(10) #> [1] 12"},{"path":"https://coro.r-lib.org/reference/iterator.html","id":null,"dir":"Reference","previous_headings":"","what":"Iterator protocol — iterator","title":"Iterator protocol — iterator","text":"iterator function implements following protocol: Calling function advances iterator. new value returned. iterator exhausted elements return, symbol quote(exhausted) returned. signals exhaustion caller. iterator signalled exhaustion, subsequent invokations must consistently return coro::exhausted() .symbol(\".__exhausted__.\"). iteration defined protocol, creating iterators free dependency. However, often simpler create iterators generators, see vignette(\"generator\"). loop iterator, simpler use loop() collect() helpers provided package.","code":"iterator <- as_iterator(1:3) # Calling the iterator advances it iterator() #> [1] 1 iterator() #> [1] 2 # This is the last value iterator() #> [1] 3 # Subsequent invokations return the exhaustion sentinel iterator() #> .__exhausted__."},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Iterator protocol — iterator","text":"","code":"exhausted() is_exhausted(x)"},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Iterator protocol — iterator","text":"x object.","code":""},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"properties","dir":"Reference","previous_headings":"","what":"Properties","title":"Iterator protocol — iterator","text":"Iterators stateful. Advancing iterator creates persistent effect R session. Also iterators one-way. advanced iterator, going back exhausted, stays exhausted. Iterators necessarily finite. can also represent infinite sequences, case trying exhaust programming error causes infinite loop.","code":""},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"the-exhausted-sentinel","dir":"Reference","previous_headings":"","what":"The exhausted sentinel","title":"Iterator protocol — iterator","text":"Termination iteration signalled via sentinel value, .symbol(\".__exhausted__.\"). Alternative designs include: condition python. rich value containing termination flag Javascript. sentinel design simple efficient solution downside. iterating collection elements inadvertently contains sentinel value, iteration terminated early. avoid mix-ups, sentinel used temporary value. created scratch function like coro::exhausted() never stored container namespace.","code":""},{"path":"https://coro.r-lib.org/reference/yield.html","id":null,"dir":"Reference","previous_headings":"","what":"Yield a value from a generator — yield","title":"Yield a value from a generator — yield","text":"yield() statement suspends generator() functions. works like return() except function continues execution yielding point called . yield() can called within loops -else branches technical reasons used anywhere R code: yield() called part function argument. Code list(yield()) illegal. yield() cross function boundaries. use lambda function passed lapply() instance.","code":""},{"path":"https://coro.r-lib.org/reference/yield.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Yield a value from a generator — yield","text":"","code":"yield(x)"},{"path":"https://coro.r-lib.org/reference/yield.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Yield a value from a generator — yield","text":"x value yield.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-104","dir":"Changelog","previous_headings":"","what":"coro 1.0.4","title":"coro 1.0.4","text":"Internal fix R-devel.","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-103","dir":"Changelog","previous_headings":"","what":"coro 1.0.3","title":"coro 1.0.3","text":"CRAN release: 2022-07-19 coro::as_iterator() method added reticulate Python objects, enabling usage like: coro::loop((elem my_py_object) ...) (#37, @t-kalinowski).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-102","dir":"Changelog","previous_headings":"","what":"coro 1.0.2","title":"coro 1.0.2","text":"CRAN release: 2021-12-03 exhaustion sentinel now .symbol(\".__exhausted__.\") instead .symbol(\"exhausted\") reduce risk collisions. also recommended never store exhaustion sentinel environment list, instead use temporary value reduce risk collisions (#35). Fixed leak occurred via JIT caching (#36).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-101","dir":"Changelog","previous_headings":"","what":"coro 1.0.1","title":"coro 1.0.1","text":"CRAN release: 2020-12-17 collect() now preserves lists data frames (#32).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-100","dir":"Changelog","previous_headings":"","what":"coro 1.0.0","title":"coro 1.0.0","text":"CRAN release: 2020-12-09 first public version coro. Python iterators created reticulate package can now composed coro generators. can also used loop() collect(). iterate() renamed loop() avoid name clash semantic conflict reticulate::iterate(). collect() calls as_iterator() input. as_iterator() now generic function (#28). Generators async functions now support .exit() expressions. also support exit expressions installed functions like withr::local_options(). requires R >= 3.5. Generator arguments forced reentry approriate context (e.g. tryCatch() context generator yielded tryCatch()). makes possible clean cancelled generators (jumping generator restart) propagate errors async functions. Generators async functions now support yielding within tryCatch() expressions. Generators async functions now disabled unexpected exit occurs (error, interrupt, restart invokation, debugger exit, etc.). Reentering generator error. Generators async functions now support stepping browser(). Set options(coro_debug = TRUE) browsing functions created coro. Use coro_debug() browsing specific functions. generator() now accepts functions one argument. first time generator called argument defined suspendable function. subsequent invokations, argument returned yield(). generator() now creates generator factories. takes function template returns function creates generator functions template. consistent languages like Javascript Python. async() function operator creates functions cooperative concurrency using later promises framework. async_generator() creates iterable functions also awaitable. iterator abstraction removed coro. replaced following protocol: iterator function. advance get new value calling . iterator signals exhaustion returning exhausted() (equivalently, quote(exhausted) symbol). Exhausted generators longer throw called . Instead, return exhausted() sentinel (#6). Fixed top-level break statements loops (#7).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-001","dir":"Changelog","previous_headings":"","what":"coro 0.0.1","title":"coro 0.0.1","text":"Initial release","code":""}]
+[{"path":[]},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"our-pledge","dir":"","previous_headings":"","what":"Our Pledge","title":"Contributor Covenant Code of Conduct","text":"members, contributors, leaders pledge make participation community harassment-free experience everyone, regardless age, body size, visible invisible disability, ethnicity, sex characteristics, gender identity expression, level experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, sexual identity orientation. pledge act interact ways contribute open, welcoming, diverse, inclusive, healthy community.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"our-standards","dir":"","previous_headings":"","what":"Our Standards","title":"Contributor Covenant Code of Conduct","text":"Examples behavior contributes positive environment community include: Demonstrating empathy kindness toward people respectful differing opinions, viewpoints, experiences Giving gracefully accepting constructive feedback Accepting responsibility apologizing affected mistakes, learning experience Focusing best just us individuals, overall community Examples unacceptable behavior include: use sexualized language imagery, sexual attention advances kind Trolling, insulting derogatory comments, personal political attacks Public private harassment Publishing others’ private information, physical email address, without explicit permission conduct reasonably considered inappropriate professional setting","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"enforcement-responsibilities","dir":"","previous_headings":"","what":"Enforcement Responsibilities","title":"Contributor Covenant Code of Conduct","text":"Community leaders responsible clarifying enforcing standards acceptable behavior take appropriate fair corrective action response behavior deem inappropriate, threatening, offensive, harmful. Community leaders right responsibility remove, edit, reject comments, commits, code, wiki edits, issues, contributions aligned Code Conduct, communicate reasons moderation decisions appropriate.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"scope","dir":"","previous_headings":"","what":"Scope","title":"Contributor Covenant Code of Conduct","text":"Code Conduct applies within community spaces, also applies individual officially representing community public spaces. Examples representing community include using official e-mail address, posting via official social media account, acting appointed representative online offline event.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"enforcement","dir":"","previous_headings":"","what":"Enforcement","title":"Contributor Covenant Code of Conduct","text":"Instances abusive, harassing, otherwise unacceptable behavior may reported community leaders responsible enforcement codeofconduct@posit.co. complaints reviewed investigated promptly fairly. community leaders obligated respect privacy security reporter incident.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"enforcement-guidelines","dir":"","previous_headings":"","what":"Enforcement Guidelines","title":"Contributor Covenant Code of Conduct","text":"Community leaders follow Community Impact Guidelines determining consequences action deem violation Code Conduct:","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_1-correction","dir":"","previous_headings":"Enforcement Guidelines","what":"1. Correction","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Use inappropriate language behavior deemed unprofessional unwelcome community. Consequence: private, written warning community leaders, providing clarity around nature violation explanation behavior inappropriate. public apology may requested.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_2-warning","dir":"","previous_headings":"Enforcement Guidelines","what":"2. Warning","title":"Contributor Covenant Code of Conduct","text":"Community Impact: violation single incident series actions. Consequence: warning consequences continued behavior. interaction people involved, including unsolicited interaction enforcing Code Conduct, specified period time. includes avoiding interactions community spaces well external channels like social media. Violating terms may lead temporary permanent ban.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_3-temporary-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"3. Temporary Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: serious violation community standards, including sustained inappropriate behavior. Consequence: temporary ban sort interaction public communication community specified period time. public private interaction people involved, including unsolicited interaction enforcing Code Conduct, allowed period. Violating terms may lead permanent ban.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"id_4-permanent-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"4. Permanent Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Demonstrating pattern violation community standards, including sustained inappropriate behavior, harassment individual, aggression toward disparagement classes individuals. Consequence: permanent ban sort public interaction within community.","code":""},{"path":"https://coro.r-lib.org/CODE_OF_CONDUCT.html","id":"attribution","dir":"","previous_headings":"","what":"Attribution","title":"Contributor Covenant Code of Conduct","text":"Code Conduct adapted Contributor Covenant, version 2.1, available https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. Community Impact Guidelines inspired [Mozilla’s code conduct enforcement ladder][https://github.com/mozilla/inclusion]. answers common questions code conduct, see FAQ https://www.contributor-covenant.org/faq. Translations available https://www.contributor-covenant.org/translations.","code":""},{"path":"https://coro.r-lib.org/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"MIT License","title":"MIT License","text":"Copyright (c) 2020 coro authors Permission hereby granted, free charge, person obtaining copy software associated documentation files (“Software”), deal Software without restriction, including without limitation rights use, copy, modify, merge, publish, distribute, sublicense, /sell copies Software, permit persons Software furnished , subject following conditions: copyright notice permission notice shall included copies substantial portions Software. SOFTWARE PROVIDED “”, WITHOUT WARRANTY KIND, EXPRESS IMPLIED, INCLUDING LIMITED WARRANTIES MERCHANTABILITY, FITNESS PARTICULAR PURPOSE NONINFRINGEMENT. EVENT SHALL AUTHORS COPYRIGHT HOLDERS LIABLE CLAIM, DAMAGES LIABILITY, WHETHER ACTION CONTRACT, TORT OTHERWISE, ARISING , CONNECTION SOFTWARE USE DEALINGS SOFTWARE.","code":""},{"path":"https://coro.r-lib.org/articles/generator.html","id":"iterators","dir":"Articles","previous_headings":"","what":"Iterators","title":"Generators","text":"Generators simple way creating iterator functions, .e. functions can call return new value. iteration protocol described ?iterator. simple iterator iterates elements 1:3: iterator exhausted, returns sentinel value signals caller values available: R normally don’t use sort iteration work vectors. Instead, use idiomatic techniques vectorised programming. Iterator functions useful specific tasks: Iterating chunks data whole data doesn’t fit memory. Generating sequences don’t know advance many elements need. sequences may complex even infinite. iterator protocol designed free dependency. However, easiest way create iterator using generator factories provided package.","code":"library(coro) iterator <- as_iterator(1:3) # Call the iterator to retrieve new values iterator() #> [1] 1 iterator() #> [1] 2 # This is the last value iterator() #> [1] 3 # This is the exhaustion sentinel iterator() #> .__exhausted__."},{"path":"https://coro.r-lib.org/articles/generator.html","id":"generators","dir":"Articles","previous_headings":"","what":"Generators","title":"Generators","text":"Generators create functions can yield, .e. suspend . generator reaches yield(value) statement returns value called return(value). However, calling generator resumes function right left . preserve state invokations, generators ideal creating iterator functions. generator() creates iterator factory. function returns fresh iterator functions: last loop generator finished iterating (one), returns exhaustion sentinel: can also create infinite iterators can’t exhausted:","code":"generate_abc <- generator(function() { for (x in letters[1:3]) { yield(x) } }) # Create the iterator abc <- generate_abc() # Use the iterator by invoking it abc() #> [1] \"a\" abc() #> [1] \"b\" # Last value abc() #> [1] \"c\" # Exhaustion sentinel abc() #> .__exhausted__. abc() #> .__exhausted__. generate_natural_numbers <- generator(function(from = 1L) { x <- from repeat { yield(x) x <- x + 1L } }) natural_numbers <- generate_natural_numbers(from = 10L) # The iterator generates new numbers forever natural_numbers() #> [1] 10 natural_numbers() #> [1] 11"},{"path":"https://coro.r-lib.org/articles/generator.html","id":"iterating","dir":"Articles","previous_headings":"","what":"Iterating","title":"Generators","text":"Iterating manually iterator function bit tricky watch exhaustion sentinel: simpler way iterate loop using iterate() helper. Within iterate(), understands iterator protocol: can also collect remaning values iterator list collect(): Beware trying exhaust infinite iterator programming error. causes infinite loop never returns, forcing user interrupt R ctrl-c. Make sure iterate infinite iterator finite amount time:","code":"abc <- generate_abc() while (!is_exhausted(x <- abc())) { print(x) } #> [1] \"a\" #> [1] \"b\" #> [1] \"c\" abc <- generate_abc() loop(for (x in abc) { print(x) }) #> [1] \"a\" #> [1] \"b\" #> [1] \"c\" abc <- generate_abc() collect(abc) #> [[1]] #> [1] \"a\" #> #> [[2]] #> [1] \"b\" #> #> [[3]] #> [1] \"c\" for (x in 1:3) { print(natural_numbers()) } #> [1] 12 #> [1] 13 #> [1] 14 collect(natural_numbers, n = 3) #> [[1]] #> [1] 15 #> #> [[2]] #> [1] 16 #> #> [[3]] #> [1] 17"},{"path":"https://coro.r-lib.org/articles/generator.html","id":"adapting-generators","dir":"Articles","previous_headings":"","what":"Adapting generators","title":"Generators","text":"generator factory can take another iterator argument modify values. pattern called adapting: modified iterator exhausted, adaptor automatically closes well: user, might want create iterator factory one-adaptor. case can use gen() instead generator(). enables pythonic style working iterators: can use general purpose adaptor adapt_map(). maps function value iterator:","code":"library(magrittr) adapt_toupper <- generator(function(i) { for (x in i) { yield(toupper(x)) } }) ABC <- generate_abc() %>% adapt_toupper() ABC() #> [1] \"A\" ABC() #> [1] \"B\" ABC() #> [1] \"C\" ABC() #> .__exhausted__. abc <- generate_abc() ABC <- gen(for (x in abc) yield(toupper(x))) collect(ABC) #> [[1]] #> [1] \"A\" #> #> [[2]] #> [1] \"B\" #> #> [[3]] #> [1] \"C\" adapt_map <- generator(function(.i, .fn, ...) { for (x in .i) { yield(.fn(x, ...)) } }) ABC <- generate_abc() %>% adapt_map(toupper) ABC() #> [1] \"A\""},{"path":"https://coro.r-lib.org/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Lionel Henry. Author, maintainer. . Copyright holder, funder.","code":""},{"path":"https://coro.r-lib.org/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Henry L (2024). coro: 'Coroutines' R. R package version 1.1.0, https://coro.r-lib.org/, https://github.com/r-lib/coro.","code":"@Manual{, title = {coro: 'Coroutines' for R}, author = {Lionel Henry}, year = {2024}, note = {R package version 1.1.0, https://coro.r-lib.org/}, url = {https://github.com/r-lib/coro}, }"},{"path":[]},{"path":"https://coro.r-lib.org/index.html","id":"overview","dir":"","previous_headings":"","what":"Overview","title":"Coroutines for R","text":"coro implements coroutines R, .e. functions can suspended resumed later . two kinds: Async functions, make straightforward program concurrently Generators iterating complex sequences Supported features: Suspending within loops /else branches Suspending within tryCatch() .exit() expressions stack-based cleanup provided local_ functions withr package Step-debugging browser() within coroutines Compatibility : Python iterators reticulate package Async operations promises package Parallel computations future package Attach package follow examples:","code":"library(coro)"},{"path":"https://coro.r-lib.org/index.html","id":"asyncawait-functions","dir":"","previous_headings":"Overview","what":"Async/await functions","title":"Coroutines for R","text":"Concurrent programming made straightforward async-await functions. Whenever waiting result may take (downloading file, computing value external process), use await(). argument await() must return promise promises package. Concurrent code based promises can quickly become hard write follow. following artificial example, wait download complete, decide launch computation external process depending property downloaded data. also handle errors specifically. Rewriting function async/await greatly simplifies code:","code":"my_async <- function() { async_download() %>% then(function(data) { if (ncol(data) > 10) { then(future::future(fib(30)), function(fib) { data / fib }) } else { data } }, onRejected = function(err) { if (inherits(err, \"download_error\")) { NULL } else { stop(err) } }) } my_async <- async(function() { data <- tryCatch( await(async_download()), download_error = function(err) NULL ) if (is.null(data)) { return(NULL) } if (ncol(data) > 10) { fib <- await(future::future(fib(30))) data <- data /fib } data })"},{"path":"https://coro.r-lib.org/index.html","id":"generators","dir":"","previous_headings":"Overview","what":"Generators","title":"Coroutines for R","text":"Generators based simple iteration protocol: Iterators functions. can advanced calling function. new value returned. exhausted iterator returns sentinel symbol exhausted. generator() function creates generator factory returns generator instances: generator instance iterator function yields values: Collect remaining values iterator collect(): Iterate iterator loop(): See vignette(\"generator\") information.","code":"# Create a generator factory generate_abc <- generator(function() { for (x in letters[1:3]) { yield(x) } }) # Create a generator instance abc <- generate_abc() abc #> #> function () #> { #> for (x in letters[1:3]) { #> yield(x) #> } #> } #> abc() #> [1] \"a\" collect(abc) #> [[1]] #> [1] \"b\" #> #> [[2]] #> [1] \"c\" loop(for (x in generate_abc()) { print(toupper(x)) }) #> [1] \"A\" #> [1] \"B\" #> [1] \"C\""},{"path":"https://coro.r-lib.org/index.html","id":"compatibility-with-the-reticulate-package","dir":"","previous_headings":"Overview","what":"Compatibility with the reticulate package","title":"Coroutines for R","text":"Python iterators imported reticulate package compatible loop() collect(): can also composed coro generators:","code":"suppressMessages(library(reticulate)) py_run_string(\" def first_n(n): num = 1 while num <= n: yield num num += 1 \") loop(for (x in py$first_n(3)) { print(x * 2) }) #> [1] 2 #> [1] 4 #> [1] 6 times <- generator(function(it, n) for (x in it) yield(x * n)) composed <- times(py$first_n(3), 10) collect(composed) #> [[1]] #> [1] 10 #> #> [[2]] #> [1] 20 #> #> [[3]] #> [1] 30"},{"path":"https://coro.r-lib.org/index.html","id":"limitations","dir":"","previous_headings":"","what":"Limitations","title":"Coroutines for R","text":"yield() await() can used loops, /else branches, tryCatch() expressions, combinations . However can’t used function arguments. cause errors: Fortunately easy rewrite code work around limitation:","code":"generator(function() { list(yield(\"foo\")) }) async(function() { list(await(foo())) }) generator(function() { x <- yield(\"foo\") list(x) }) async(function() { x <- await(foo()) list(x) })"},{"path":"https://coro.r-lib.org/index.html","id":"how-does-it-work","dir":"","previous_headings":"","what":"How does it work","title":"Coroutines for R","text":"Coroutines abstraction state machines languages support . Conversely, can implement coroutines rewriting code source provided user state machine. Pass internals = TRUE print methods coroutines reveal state machine running hood: Despite transformation source code, browser() step-debugging still work expect. coro keeps track source references original code.","code":"print(generate_abc, internals = TRUE) #> #> function () #> { #> for (x in letters[1:3]) { #> yield(x) #> } #> } #> #> State machine: #> { #> if (exhausted) { #> return(invisible(exhausted())) #> } #> repeat switch(state[[1L]], `1` = { #> iterators[[2L]] <- as_iterator(user(letters[1:3])) #> state[[1L]] <- 2L #> state[[2L]] <- 1L #> }, `2` = { #> repeat switch(state[[2L]], `1` = { #> if ({ #> iterator <- iterators[[2L]] #> if (is_exhausted(elt <- iterator())) { #> FALSE #> } else { #> user_env[[\"x\"]] <- elt #> TRUE #> } #> }) { #> state[[2L]] <- 2L #> } else { #> break #> } #> }, `2` = { #> user({ #> x #> }) #> state[[2L]] <- 3L #> suspend() #> return(last_value()) #> }, `3` = { #> .last_value <- if (missing(arg)) NULL else arg #> state[[2L]] <- 1L #> }) #> iterators[[2L]] <- NULL #> length(state) <- 1L #> break #> }) #> exhausted <- TRUE #> invisible(exhausted()) #> }"},{"path":"https://coro.r-lib.org/index.html","id":"acknowledgements","dir":"","previous_headings":"","what":"Acknowledgements","title":"Coroutines for R","text":"regenerator Javascript package uses similar transformation implement generators async functions older versions Javascript. Gabor Csardi many interesting discussions concurrency design coro.","code":""},{"path":"https://coro.r-lib.org/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Coroutines for R","text":"Install development version github :","code":"# install.packages(\"devtools\") devtools::install_github(\"r-lib/coro\", build_vignettes = TRUE)"},{"path":"https://coro.r-lib.org/index.html","id":"code-of-conduct","dir":"","previous_headings":"","what":"Code of Conduct","title":"Coroutines for R","text":"Please note coro project released Contributor Code Conduct. contributing project, agree abide terms.","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":null,"dir":"Reference","previous_headings":"","what":"Transform an object to an iterator — as_iterator","title":"Transform an object to an iterator — as_iterator","text":"as_iterator() generic function transforms input iterator function. default implementation follows: Functions returned . objects assumed vectors length() [[ methods. Methods must return functions implement coro's iterator protocol. as_iterator() called coro RHS loops. applies within generators, async functions, loop().","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Transform an object to an iterator — as_iterator","text":"","code":"as_iterator(x) # Default S3 method as_iterator(x)"},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Transform an object to an iterator — as_iterator","text":"x object.","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Transform an object to an iterator — as_iterator","text":"iterable function.","code":""},{"path":"https://coro.r-lib.org/reference/as_iterator.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Transform an object to an iterator — as_iterator","text":"","code":"as_iterator(1:3) #> function () #> { #> if (i == n) { #> return(exhausted()) #> } #> i <<- i + 1L #> x[[i]] #> } #> #> i <- as_iterator(1:3) loop(for (x in i) print(x)) #> [1] 1 #> [1] 2 #> [1] 3"},{"path":"https://coro.r-lib.org/reference/async.html","id":null,"dir":"Reference","previous_headings":"","what":"Make an async function — async","title":"Make an async function — async","text":"async() functions building blocks cooperative concurrency. concurrent jointly managed scheduler charge running . cooperative decide can longer make quick progress need await result. done await() keyword suspends async function gives control back scheduler. scheduler waits next async operation ready make progress. async framework used async() functions implemented later promises packages: can chain async functions created coro promises. can await promises. can also await futures created future package coercible promises.","code":""},{"path":"https://coro.r-lib.org/reference/async.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Make an async function — async","text":"","code":"async(fn) await(x)"},{"path":"https://coro.r-lib.org/reference/async.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Make an async function — async","text":"fn anonymous function within await() calls allowed. x awaitable value, .e. promise.","code":""},{"path":"https://coro.r-lib.org/reference/async.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Make an async function — async","text":"function returns promises::promise() invisibly.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/async.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Make an async function — async","text":"","code":"# This async function counts down from `n`, sleeping for 2 seconds # at each iteration: async_count_down <- async(function(n) { while (n > 0) { cat(\"Down\", n, \"\\n\") await(async_sleep(2)) n <- n - 1 } }) # This async function counts up until `stop`, sleeping for 0.5 # seconds at each iteration: async_count_up <- async(function(stop) { n <- 1 while (n <= stop) { cat(\"Up\", n, \"\\n\") await(async_sleep(0.5)) n <- n + 1 } }) # You can run these functions concurrently using `promise_all()` if (interactive()) { promises::promise_all(async_count_down(5), async_count_up(5)) }"},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":null,"dir":"Reference","previous_headings":"","what":"Collect elements of an asynchronous iterator — async_collect","title":"Collect elements of an asynchronous iterator — async_collect","text":"async_collect() takes asynchronous iterator, .e. iterable function also awaitable. async_collect() returns awaitable eventually resolves list containing values returned iterator. values collected exhaustion unless n supplied. collection grown geometrically performance.","code":""},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Collect elements of an asynchronous iterator — async_collect","text":"","code":"async_collect(x, n = NULL)"},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Collect elements of an asynchronous iterator — async_collect","text":"x iterator function. n number elements collect. x infinite sequence, n must supplied prevent infinite loop.","code":""},{"path":"https://coro.r-lib.org/reference/async_collect.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Collect elements of an asynchronous iterator — async_collect","text":"","code":"# Emulate an async stream by yielding promises that resolve to the # elements of the input vector generate_stream <- async_generator(function(x) for (elt in x) yield(elt)) # You can await `async_collect()` in an async function. Once the # list of values is resolved, the async function resumes. async(function() { stream <- generate_stream(1:3) values <- await(async_collect(stream)) values }) #> #> function () #> { #> stream <- generate_stream(1:3) #> values <- await(async_collect(stream)) #> values #> } #> "},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":null,"dir":"Reference","previous_headings":"","what":"Construct an async generator — async_generator","title":"Construct an async generator — async_generator","text":"async generator constructs iterable functions also awaitables. support yield() await() syntax. async iterator can looped within async functions iterators using await_each() input loop. iteration protocol derived one described iterator. async iterator always returns promise. iterator exhausted, returns resolved promise exhaustion sentinel.","code":""},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Construct an async generator — async_generator","text":"","code":"async_generator(fn) await_each(x)"},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Construct an async generator — async_generator","text":"fn anonymous function describing async generator within await() calls allowed. x awaitable value, .e. promise.","code":""},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Construct an async generator — async_generator","text":"generator factory. Generators constructed factory always return promises::promise().","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/async_generator.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Construct an async generator — async_generator","text":"","code":"# Creates awaitable functions that transform their inputs into a stream generate_stream <- async_generator(function(x) for (elt in x) yield(elt)) # Maps a function to a stream async_map <- async_generator(function(.i, .fn, ...) { for (elt in await_each(.i)) { yield(.fn(elt, ...)) } }) # Example usage: if (interactive()) { library(magrittr) generate_stream(1:3) %>% async_map(`*`, 2) %>% async_collect() }"},{"path":"https://coro.r-lib.org/reference/async_ops.html","id":null,"dir":"Reference","previous_headings":"","what":"Async operations — async_ops","title":"Async operations — async_ops","text":"Customisation point async package concurrency framework defines \"\" operation. Assign result async_ops() .__coro_async_ops__. symbol namespace.","code":""},{"path":"https://coro.r-lib.org/reference/async_ops.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Async operations — async_ops","text":"","code":"async_ops(package, then, as_promise)"},{"path":"https://coro.r-lib.org/reference/async_ops.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Async operations — async_ops","text":"package package name framework string. async() async_generator() check package installed runtime. function two arguments. first argument promise object (created as_promise). second argument callback function must called promise object resolved. as_promise function one argument. -op passed promise object, otherwise wrap value resolved promise.","code":""},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":null,"dir":"Reference","previous_headings":"","what":"Sleep asynchronously — async_sleep","title":"Sleep asynchronously — async_sleep","text":"Sleep asynchronously","code":""},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Sleep asynchronously — async_sleep","text":"","code":"async_sleep(seconds)"},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Sleep asynchronously — async_sleep","text":"seconds number second sleep.","code":""},{"path":"https://coro.r-lib.org/reference/async_sleep.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Sleep asynchronously — async_sleep","text":"chainable promise.","code":""},{"path":"https://coro.r-lib.org/reference/collect.html","id":null,"dir":"Reference","previous_headings":"","what":"Iterate over iterator functions — collect","title":"Iterate over iterator functions — collect","text":"loop() collect() helpers iterating iterator functions generators. loop() takes loop expression collection can iterator function. collect() loops iterator collects values list.","code":""},{"path":"https://coro.r-lib.org/reference/collect.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Iterate over iterator functions — collect","text":"","code":"collect(x, n = NULL) loop(loop)"},{"path":"https://coro.r-lib.org/reference/collect.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Iterate over iterator functions — collect","text":"x iterator function. n number elements collect. x infinite sequence, n must supplied prevent infinite loop. loop loop expression.","code":""},{"path":"https://coro.r-lib.org/reference/collect.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Iterate over iterator functions — collect","text":"collect() returns list values; loop() returns exhausted() sentinel, invisibly.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/collect.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Iterate over iterator functions — collect","text":"","code":"generate_abc <- generator(function() for (x in letters[1:3]) yield(x)) abc <- generate_abc() # Collect 1 element: collect(abc, n = 1) #> [[1]] #> [1] \"a\" #> # Collect all remaining elements: collect(abc) #> list() # With exhausted iterators collect() returns an empty list: collect(abc) #> list() # With loop() you can use `for` loops with iterators: abc <- generate_abc() loop(for (x in abc) print(x)) #> [1] \"a\" #> [1] \"b\" #> [1] \"c\""},{"path":"https://coro.r-lib.org/reference/coro-package.html","id":null,"dir":"Reference","previous_headings":"","what":"coro: 'Coroutines' for R — coro-package","title":"coro: 'Coroutines' for R — coro-package","text":"Provides 'coroutines' R, family functions can suspended resumed later . includes 'async' functions (await) generators (yield). 'Async' functions based concurrency framework 'promises' package. Generators based dependency free iteration protocol defined 'coro' compatible iterators 'reticulate' package.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/coro-package.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"coro: 'Coroutines' for R — coro-package","text":"Maintainer: Lionel Henry lionel@posit.co contributors: Posit Software, PBC [copyright holder, funder]","code":""},{"path":"https://coro.r-lib.org/reference/coro_debug.html","id":null,"dir":"Reference","previous_headings":"","what":"Debug a generator or async function — coro_debug","title":"Debug a generator or async function — coro_debug","text":"Call coro_debug() generator(), async(), async_generator() function enable step-debugging. Alternatively, set options(coro_debug = TRUE) step-debugging functions created coro.","code":""},{"path":"https://coro.r-lib.org/reference/coro_debug.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Debug a generator or async function — coro_debug","text":"","code":"coro_debug(fn, value = TRUE)"},{"path":"https://coro.r-lib.org/reference/coro_debug.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Debug a generator or async function — coro_debug","text":"fn generator factory async function. value Whether debug function.","code":""},{"path":"https://coro.r-lib.org/reference/generator.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a generator function — generator","title":"Create a generator function — generator","text":"generator() creates generator factory. generator iterator function can pause execution yield() resume left . manage state , generators easiest way create iterators. See vignette(\"generator\"). following rules apply: Yielded values terminate generator. call generator , execution resumes right yielding point. local variables preserved. Returned values terminate generator. called return(), generator keeps returning exhausted() sentinel. Generators compatible features based iterator protocol loop() collect().","code":""},{"path":"https://coro.r-lib.org/reference/generator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a generator function — generator","text":"","code":"generator(fn) gen(expr)"},{"path":"https://coro.r-lib.org/reference/generator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a generator function — generator","text":"fn function template generators. function can yield() values. Within generator, loops iterator support. expr yielding expression.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/reference/generator.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a generator function — generator","text":"","code":"# A generator statement creates a generator factory. The # following generator yields three times and then returns `\"d\"`. # Only the yielded values are visible to the callers. generate_abc <- generator(function() { yield(\"a\") yield(\"b\") yield(\"c\") \"d\" }) # Equivalently: generate_abc <- generator(function() { for (x in c(\"a\", \"b\", \"c\")) { yield(x) } }) # The factory creates generator instances. They are iterators # that you can call successively to obtain new values: abc <- generate_abc() abc() #> [1] \"a\" abc() #> [1] \"b\" # Once a generator has returned it keeps returning `exhausted()`. # This signals to its caller that new values can no longer be # produced. The generator is exhausted: abc() #> [1] \"c\" abc() #> .__exhausted__. # You can only exhaust a generator once but you can always create # new ones from a factory: abc <- generate_abc() abc() #> [1] \"a\" # As generators implement the coro iteration protocol, you can use # coro tools like `loop()`. It makes it possible to loop over # iterators with `for` expressions: loop(for (x in abc) print(x)) #> [1] \"b\" #> [1] \"c\" # To gather values of an iterator in a list, use `collect()`. Pass # the `n` argument to collect that number of elements from a # generator: abc <- generate_abc() collect(abc, 1) #> [[1]] #> [1] \"a\" #> # Or drain all remaining elements: collect(abc) #> list() # coro provides a short syntax `gen()` for creating one-off # generator _instances_. It is handy to adapt existing iterators: numbers <- 1:10 odds <- gen(for (x in numbers) if (x %% 2 != 0) yield(x)) squares <- gen(for (x in odds) yield(x^2)) greetings <- gen(for (x in squares) yield(paste(\"Hey\", x))) collect(greetings) #> [[1]] #> [1] \"Hey 1\" #> #> [[2]] #> [1] \"Hey 9\" #> #> [[3]] #> [1] \"Hey 25\" #> #> [[4]] #> [1] \"Hey 49\" #> #> [[5]] #> [1] \"Hey 81\" #> # Arguments passed to generator instances are returned from the # `yield()` statement on reentry: new_tally <- generator(function() { count <- 0 while (TRUE) { i <- yield(count) count <- count + i } }) tally <- new_tally() tally(1) #> [1] 0 tally(2) #> [1] 2 tally(10) #> [1] 12"},{"path":"https://coro.r-lib.org/reference/iterator.html","id":null,"dir":"Reference","previous_headings":"","what":"Iterator protocol — iterator","title":"Iterator protocol — iterator","text":"iterator function implements following protocol: Calling function advances iterator. new value returned. iterator exhausted elements return, symbol quote(exhausted) returned. signals exhaustion caller. iterator signalled exhaustion, subsequent invokations must consistently return coro::exhausted() .symbol(\".__exhausted__.\"). iterator function may close argument taking boolean values. passed TRUE value, indicates early termination iterator given opportunity clean resources. Cleanup must performed , even iterator called multiple times close = TRUE. iterator allowed close argument. Iterator drivers must check presence argument. present, iterator can dropped without cleanup. iterator passed close = TRUE must return coro::exhausted() closed, iterator must return coro::exhausted() called . iteration defined protocol, creating iterators free dependency. However, often simpler create iterators generators, see vignette(\"generator\"). loop iterator, simpler use loop() collect() helpers provided package.","code":"iterator <- as_iterator(1:3) # Calling the iterator advances it iterator() #> [1] 1 iterator() #> [1] 2 # This is the last value iterator() #> [1] 3 # Subsequent invokations return the exhaustion sentinel iterator() #> .__exhausted__."},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Iterator protocol — iterator","text":"","code":"exhausted() is_exhausted(x)"},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Iterator protocol — iterator","text":"x object.","code":""},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"properties","dir":"Reference","previous_headings":"","what":"Properties","title":"Iterator protocol — iterator","text":"Iterators stateful. Advancing iterator creates persistent effect R session. Also iterators one-way. advanced iterator, going back exhausted, stays exhausted. Iterators necessarily finite. can also represent infinite sequences, case trying exhaust programming error causes infinite loop.","code":""},{"path":"https://coro.r-lib.org/reference/iterator.html","id":"the-exhausted-sentinel","dir":"Reference","previous_headings":"","what":"The exhausted sentinel","title":"Iterator protocol — iterator","text":"Termination iteration signalled via sentinel value, .symbol(\".__exhausted__.\"). Alternative designs include: condition python. rich value containing termination flag Javascript. sentinel design simple efficient solution downside. iterating collection elements inadvertently contains sentinel value, iteration terminated early. avoid mix-ups, sentinel used temporary value. created scratch function like coro::exhausted() never stored container namespace.","code":""},{"path":"https://coro.r-lib.org/reference/yield.html","id":null,"dir":"Reference","previous_headings":"","what":"Yield a value from a generator — yield","title":"Yield a value from a generator — yield","text":"yield() statement suspends generator() functions. works like return() except function continues execution yielding point called . yield() can called within loops -else branches technical reasons used anywhere R code: yield() called part function argument. Code list(yield()) illegal. yield() cross function boundaries. use lambda function passed lapply() instance.","code":""},{"path":"https://coro.r-lib.org/reference/yield.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Yield a value from a generator — yield","text":"","code":"yield(x)"},{"path":"https://coro.r-lib.org/reference/yield.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Yield a value from a generator — yield","text":"x value yield.","code":""},{"path":[]},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-110","dir":"Changelog","previous_headings":"","what":"coro 1.1.0","title":"coro 1.1.0","text":"Iterator functions now allowed close argument. , called close = TRUE value iteration terminated early. gives opportunity clean resources. Generators now run .exit() expressions closed. Iterators managed coro::loop() generator loops now cleaned terminated early, either error break (#52). Implicit explicit return values generators longer yielded. consistent Javascript Python simplifies certain idioms (#51). Generators async functions assigned namespaces longer produce R CMD check notes visible bindings (#40).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-105","dir":"Changelog","previous_headings":"","what":"coro 1.0.5","title":"coro 1.0.5","text":"CRAN release: 2024-10-15 Async functions created coro::async() now return promises::promise() invisibly (#46, @shikokuchuo). Fixes CRAN checks.","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-104","dir":"Changelog","previous_headings":"","what":"coro 1.0.4","title":"coro 1.0.4","text":"CRAN release: 2024-03-11 Internal fix R-devel.","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-103","dir":"Changelog","previous_headings":"","what":"coro 1.0.3","title":"coro 1.0.3","text":"CRAN release: 2022-07-19 coro::as_iterator() method added reticulate Python objects, enabling usage like: coro::loop((elem my_py_object) ...) (#37, @t-kalinowski).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-102","dir":"Changelog","previous_headings":"","what":"coro 1.0.2","title":"coro 1.0.2","text":"CRAN release: 2021-12-03 exhaustion sentinel now .symbol(\".__exhausted__.\") instead .symbol(\"exhausted\") reduce risk collisions. also recommended never store exhaustion sentinel environment list, instead use temporary value reduce risk collisions (#35). Fixed leak occurred via JIT caching (#36).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-101","dir":"Changelog","previous_headings":"","what":"coro 1.0.1","title":"coro 1.0.1","text":"CRAN release: 2020-12-17 collect() now preserves lists data frames (#32).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-100","dir":"Changelog","previous_headings":"","what":"coro 1.0.0","title":"coro 1.0.0","text":"CRAN release: 2020-12-09 first public version coro. Python iterators created reticulate package can now composed coro generators. can also used loop() collect(). iterate() renamed loop() avoid name clash semantic conflict reticulate::iterate(). collect() calls as_iterator() input. as_iterator() now generic function (#28). Generators async functions now support .exit() expressions. also support exit expressions installed functions like withr::local_options(). requires R >= 3.5. Generator arguments forced reentry approriate context (e.g. tryCatch() context generator yielded tryCatch()). makes possible clean cancelled generators (jumping generator restart) propagate errors async functions. Generators async functions now support yielding within tryCatch() expressions. Generators async functions now disabled unexpected exit occurs (error, interrupt, restart invokation, debugger exit, etc.). Reentering generator error. Generators async functions now support stepping browser(). Set options(coro_debug = TRUE) browsing functions created coro. Use coro_debug() browsing specific functions. generator() now accepts functions one argument. first time generator called argument defined suspendable function. subsequent invokations, argument returned yield(). generator() now creates generator factories. takes function template returns function creates generator functions template. consistent languages like Javascript Python. async() function operator creates functions cooperative concurrency using later promises framework. async_generator() creates iterable functions also awaitable. iterator abstraction removed coro. replaced following protocol: iterator function. advance get new value calling . iterator signals exhaustion returning exhausted() (equivalently, quote(exhausted) symbol). Exhausted generators longer throw called . Instead, return exhausted() sentinel (#6). Fixed top-level break statements loops (#7).","code":""},{"path":"https://coro.r-lib.org/news/index.html","id":"coro-001","dir":"Changelog","previous_headings":"","what":"coro 0.0.1","title":"coro 0.0.1","text":"Initial release","code":""}]
diff --git a/sitemap.xml b/sitemap.xml
index fc028cf..bef1aad 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -1,69 +1,25 @@
-
-
-
- https://coro.r-lib.org/404.html
-
-
- https://coro.r-lib.org/CODE_OF_CONDUCT.html
-
-
- https://coro.r-lib.org/LICENSE-text.html
-
-
- https://coro.r-lib.org/LICENSE.html
-
-
- https://coro.r-lib.org/articles/generator.html
-
-
- https://coro.r-lib.org/articles/index.html
-
-
- https://coro.r-lib.org/authors.html
-
-
- https://coro.r-lib.org/index.html
-
-
- https://coro.r-lib.org/news/index.html
-
-
- https://coro.r-lib.org/reference/as_iterator.html
-
-
- https://coro.r-lib.org/reference/async.html
-
-
- https://coro.r-lib.org/reference/async_collect.html
-
-
- https://coro.r-lib.org/reference/async_generator.html
-
-
- https://coro.r-lib.org/reference/async_ops.html
-
-
- https://coro.r-lib.org/reference/async_sleep.html
-
-
- https://coro.r-lib.org/reference/collect.html
-
-
- https://coro.r-lib.org/reference/coro-package.html
-
-
- https://coro.r-lib.org/reference/coro_debug.html
-
-
- https://coro.r-lib.org/reference/generator.html
-
-
- https://coro.r-lib.org/reference/index.html
-
-
- https://coro.r-lib.org/reference/iterator.html
-
-
- https://coro.r-lib.org/reference/yield.html
-
+
+https://coro.r-lib.org/404.html
+https://coro.r-lib.org/CODE_OF_CONDUCT.html
+https://coro.r-lib.org/LICENSE-text.html
+https://coro.r-lib.org/LICENSE.html
+https://coro.r-lib.org/articles/generator.html
+https://coro.r-lib.org/articles/index.html
+https://coro.r-lib.org/authors.html
+https://coro.r-lib.org/index.html
+https://coro.r-lib.org/news/index.html
+https://coro.r-lib.org/reference/as_iterator.html
+https://coro.r-lib.org/reference/async.html
+https://coro.r-lib.org/reference/async_collect.html
+https://coro.r-lib.org/reference/async_generator.html
+https://coro.r-lib.org/reference/async_ops.html
+https://coro.r-lib.org/reference/async_sleep.html
+https://coro.r-lib.org/reference/collect.html
+https://coro.r-lib.org/reference/coro-package.html
+https://coro.r-lib.org/reference/coro_debug.html
+https://coro.r-lib.org/reference/generator.html
+https://coro.r-lib.org/reference/index.html
+https://coro.r-lib.org/reference/iterator.html
+https://coro.r-lib.org/reference/yield.html
+