diff options
author | c-blake <c-blake@users.noreply.github.com> | 2020-11-04 10:56:22 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-04 16:56:22 +0100 |
commit | f17555770e816580b475674be23458da51b10dfd (patch) | |
tree | 5e6dbb605c693811762224e8866363ed3c15bcf0 /doc/manual.rst | |
parent | 7d640e0943679a772f9595ef3be56fe2158b0912 (diff) | |
download | Nim-f17555770e816580b475674be23458da51b10dfd.tar.gz |
Clarify the sense in which Nim supports recursive iterators in the (#15834)
manual, the tutorial, and the `tbintree` test.
Diffstat (limited to 'doc/manual.rst')
-rw-r--r-- | doc/manual.rst | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/doc/manual.rst b/doc/manual.rst index d09bb4c76..d9f9cc9b9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4031,10 +4031,13 @@ Closure iterators and inline iterators have some restrictions: 1. For now, a closure iterator cannot be executed at compile time. 2. ``return`` is allowed in a closure iterator but not in an inline iterator (but rarely useful) and ends the iteration. -3. Neither inline nor closure iterators can be recursive. +3. Neither inline nor closure iterators can be (directly)* recursive. 4. Neither inline nor closure iterators have the special ``result`` variable. 5. Closure iterators are not supported by the js backend. +(*) Closure iterators can be co-recursive with a factory proc which results +in similar syntax to a recursive iterator. More details follow. + Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly default to being inline, but this may change in future versions of the implementation. @@ -4129,7 +4132,41 @@ parameters of an outer factory proc: for f in foo(): echo f +The call can be made more like an inline iterator with a for loop macro: + +.. code-block:: nim + import macros + macro toItr(x: ForLoopStmt): untyped = + let expr = x[0] + let call = x[1][1] # Get foo out of toItr(foo) + let body = x[2] + result = quote do: + block: + let itr = `call` + for `expr` in itr(): + `body` + + for f in toItr(mycount(1, 4)): # using early `proc mycount` + echo f + +Because of full backend function call aparatus involvment, closure iterator +invocation is typically higher cost than inline iterators. Adornment by +a macro wrapper at the call site like this is a possibly useful reminder. + +The factory ``proc``, as an ordinary procedure, can be recursive. The +above macro allows such recursion to look much like a recursive iterator +would. For example: + +.. code-block:: nim + proc recCountDown(n: int): iterator(): int = + result = iterator(): int = + if n > 0: + yield n + for e in toItr(recCountDown(n - 1)): + yield e + for i in toItr(recCountDown(6)): # Emits: 6 5 4 3 2 1 + echo i Converters ========== @@ -4619,8 +4656,8 @@ The following example shows a generic binary tree can be modeled: iterator preorder*[T](root: BinaryTree[T]): T = # Preorder traversal of a binary tree. - # Since recursive iterators are not yet implemented, - # this uses an explicit stack (which is more efficient anyway): + # This uses an explicit stack (which is more efficient than + # a recursive iterator factory). var stack: seq[BinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() |