Generator (computer programming): Difference between revisions

Content deleted Content added
m avoid boxing in the first Java example and simplify the second example by using a method reference instead of a lambda (and also fix a missing semicolon)
Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.5
 
(95 intermediate revisions by 53 users not shown)
Line 1:
{{Short description|Routine that generates a sequence of values}}
{{other uses|Generator (disambiguation)#Computing}}
 
{{Refimprove|date=July 2007}}
 
In [[computer science]], a '''generator''' is a special [[subroutine|routine]] that can be used to control the [[iteration]] behaviour of a [[control flow#Loops|loop]]. In fact, allAll generators are also [[iterator]]s.<ref>[https://stackoverflow.com/questionsq/1022564/what- What is- the- difference- between- an-iterator- Iterator and- a-generator Generator?]</ref> A generator is very similar to a [[Function (computer programming)|function]] that returns an [[Array (data structure)|array]], in that a generator has [[Parameter (computer programming)|parameters]], can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator ''yields'' the values one at a time, which requires less [[Computer memory|memory]] and allows the caller to get started processing the first few values immediately. In short, a generator ''looks like'' a function but ''behaves like'' an [[iterator]].
 
Generators can be implemented in terms of more expressive [[control flow]] constructs, such as [[coroutine]]s or first-class [[continuation]]s.<ref>{{cite web
Line 11 ⟶ 12:
| title = General ways to traverse collections in Scheme
| url = http://okmij.org/ftp/Scheme/enumerators-callcc.html
}}</ref> Generators, also known as semicoroutines,<ref name="Ralston2000">{{cite book|author=Anthony Ralston|title=Encyclopedia of computer science|url=https://books.google.com/books?id=yQ9LAQAAIAAJ|accessdateaccess-date=11 May 2013|year=2000|publisher=Nature Pub. Group|isbn=978-1-56159-248-7}}</ref> are a special case of (and weaker than) coroutines, in that they always yield control back to the caller (when passing a value back), rather than specifying a coroutine to jump to; see [[Coroutine#Comparison with generatorsGenerators|comparison of coroutines with generators]].
 
==Uses==
Line 21 ⟶ 22:
When eager evaluation is desirable (primarily when the sequence is finite, as otherwise evaluation will never terminate), one can either convert to a [[List (abstract data type)|list]], or use a parallel construction that creates a list instead of a generator. For example, in Python a generator <code>g</code> can be evaluated to a list <code>l</code> via <code>l = list(g)</code>, while in [[F Sharp programming language|F#]] the sequence expression <code>seq { ... }</code> evaluates lazily (a generator or sequence) but <code>[ ... ]</code> evaluates eagerly (a list).
 
In the presence of generators, loop constructs of a language – such as for and while – can be reduced into a single loop ... end loop construct; all the usual loop constructs can then be comfortably simulated by using suitable generators in the right way. For example, a ranged loop like <code>for x = 1 to 10</code> can be implemented as iteration through a generator, as in Python's <code>for x in xrangerange(1, 10)</code>. Further, <code>break</code> can be implemented as sending ''finish'' to the generator and then using <code>continue</code> in the loop.
 
==Languages providing generators==
==Timeline==
 
Generators first appeared in [[CLU (programming language)|CLU]] (1975),<ref>{{cite web
| last = Liskov
| first = Barbara
| authorlinkauthor-link = Barbara Liskov
| date = April 1992
| title = A History of CLU
| url = http://www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-561.pdf
| access-date = 2006-01-05
| format = pdf
| archive-url = https://web.archive.org/web/20030917041834/http://www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-561.pdf
}}</ref> were a prominent feature in the string manipulation language [[Icon (programming language)|Icon]] (1977) and are now available in [[Python (programming language)|Python]],<ref name=python>
| archive-date = 2003-09-17
| url-status = dead
}}</ref> were a prominent feature in the string manipulation language [[Icon (programming language)|Icon]] (1977) and are now available in [[Python (programming language)|Python]] (2001),<ref name=python>
Python Enhancement Proposals:
[https://www.python.org/dev/peps/pep-0255/ PEP 255: Simple Generators],
Line 40 ⟶ 44:
</ref> [[C Sharp (programming language)|C#]],<ref>
[http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx yield (C# Reference)]
</ref> [[Ruby (programming language)|Ruby]], the[[PHP]],<ref>{{Cite laterweb|url=https://www.php.net/manual/en/language.generators.overview.php|title versions= ofPHP: Generators overview - Manual}}</ref> [[ECMAScript]] (as of [[ECMAScript#6th_Edition_–_ECMAScript_2015|ES6/ES2015]]), and other languages. In CLU and C#, generators are called ''iterators'', and in Ruby, ''enumerators''.
 
===Lisp===
 
The final [[Common Lisp]] standard does not natively provide generators, yet various library implementations exist, such as [httphttps://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html#SECTION003400000000000000000 SERIES] documented in CLtL2 or [https://web.archive.org/web/20110723043455/http://cliki.net/pygen pygen].
 
===CLU===
 
A yield statement is used to implement iterators over user-defined data abstractions.<ref name=Liskov1977>{{cite journal | citeseerx=10.1.1.112.656 | last1 = Liskov | first1 = B. | last2 = Snyder | first2 = A. | last3 = Atkinson | first3 = R. | last4 = Schaffert | first4 = C. | title = Abstraction mechanisms in CLU | journal = Communications of the ACM | volume = 20 | issue = 8 | year = 1977 | accessdatepages = 564–576 | access-date = <!-- 24 May 2013 --> | doi = 10.1145/359763.359789 | s2cid = 17343380 }}</ref>
 
<syntaxhighlight lang="text">
Line 70 ⟶ 74:
 
Printing squares from 0 to 20 can be achieved using a co-routine by writing:
<syntaxhighlight lang="icon">
<pre>
local squares, j
squares := create (seq(0) ^ 2)
Line 78 ⟶ 82:
else
break
</syntaxhighlight>
</pre>
 
However, most of the time custom generators are implemented with the "suspend" keyword which functions exactly like the "yield" keyword in CLU.
 
===Jq===
 
As in Icon, in [[Jq (programming language)|jq]] every expression is a generator. The infinite generator of primes can serve as an example:
 
<pre>
def primes:
def sieve(g):
first(g) as $n
| $n, sieve(g | select((. % $n) != 0))
;
sieve(range(2; infinite))
;
</pre>
 
===C===
 
[[C (programming language)|C]] does not have generator functions as a [[language construct]], but, as they are a subset of [[coroutines]], it is simple to implement them using any framework that implements stackful coroutines, such as libdill.<ref>{{cite web|url=http://libdill.org|title=Structured Concurrency for C}}</ref>. On POSIX platforms, when the cost of [[context switching]] per iteration is not a concern, and/or full [[Parallel_computing|parallelism]] rather than merely [[Concurrency (computer_science)|concurrency]] is desired, a very simple generator function framework can be implemented using [[pthreads]] and [[Anonymous_pipe|pipes]].
 
===C++===
 
It is possible to introduce generators into C++ using pre-processor macros. The resulting code might have aspects that are very different from native C++., but the generator syntax can be very uncluttered.<ref>{{Cite Aweb|url very= goodhttp://www.codeproject.com/KB/cpp/cpp_generators.aspx|title example= canGenerators bein foundC++|date at= 21 September 2008|access-date = 9 January 2012|archive-date = 7 February 2019|archive-url = https://web.<ref>httparchive.org/web/20190207185018/https://www.codeproject.com/KB/cpp/cpp_generators.aspx|url-status = dead}}</ref> The set of pre-processor macros defined in this source allow generators defined with the syntax as in the following example:
 
<syntaxhighlight lang="cpp">$generator(descent) {
int i;
$generator(descent)
{
// place for all variables used in the generator
int i; // our counter
 
// place the constructor of our generator, e.g.
Line 117 ⟶ 104:
$emit(int) // will emit int values. Start of body of the generator.
for (i = 10; i > 0; --i)
$yield(i); // a.k.a.similar to yield in Python,
// returns next number in [1..10], reversed.
$stop; // stop, end of sequence. End of body of the generator.
};</syntaxhighlight>
};
</syntaxhighlight>
 
This can then be iterated using:
 
<syntaxhighlight lang="cpp">int main(int argc, char* argv[]) {
int main(int argc, char* argv[])
{
descent gen;
for (int n; gen(n);) // "get next" generator invocation
printf("next number is %d\n", n);
return 0;
}</syntaxhighlight>
}
</syntaxhighlight>
 
Moreover, [[C++11]] allows [[foreach loop]]s to be applied to any class that provides the <code>begin</code> and <code>end</code> functions. It's then possible to write generator-like classes by defining both the iterable methods (<code>begin</code> and <code>end</code>) and the iterator methods (<code>operator!=</code>, <code>operator++</code> and <code>operator*</code>) in the same class. For example, it is possible to write the following program:
 
<syntaxhighlight lang="cpp">#include <iostream>
 
#include <iostream>
int main() {
for (int i: range(10)) {
{
for (int i: range(10))
{
std::cout << i << std::endl;
}
return 0;
}</syntaxhighlight>
}
</syntaxhighlight>
 
A basic range implementation would look like that:
 
<syntaxhighlight lang="cpp">
class range {
{
private:
int last;
Line 173 ⟶ 152:
int operator*() const { return iter; }
};
</syntaxhighlight>Furthermore, [[C++20]] formally introduced support for coroutines,<ref>{{Cite web |title=Coroutines (C++20) - cppreference.com |url=https://en.cppreference.com/w/cpp/language/coroutines.html |access-date=2025-07-16 |website=en.cppreference.com}}</ref> which can be used to implement generators.<ref>{{Cite web |last=Carter |first=Casey |last2=Baker |first2=Lewis |last3=Jabot |first3=Corentin |title=std::generator implementation in C++20 |url=https://godbolt.org/z/5hcaPcfvP |access-date=2025-07-16 |website=godbolt.org |language=en}}</ref> [[C++23]] introduced [https://en.cppreference.com/w/cpp/coroutine/generator.html std::generator] in the standard library, making it much easier to implement generators. For example, a basic range generator can be implemented as:<syntaxhighlight lang="cpp">
</syntaxhighlight>
#include <generator>
 
std::generator<int> range(int n) {
for (int i = 0; i < n; ++i) {
co_yield i;
}
}
</syntaxhighlight>It can be iterated using [[foreach loop]]s:<syntaxhighlight lang="cpp">#include <iostream>
 
int main() {
for (int i: range(10)) {
std::cout << i << std::endl;
}
return 0;
}</syntaxhighlight>
 
===Perl===
Line 200 ⟶ 194:
 
</syntaxhighlight>
 
===Raku===
 
Example parallel to Icon uses Raku (formerly/aka Perl 6) Range class as one of several ways to achieve generators with the language.
 
Printing squares from 0 to 20 can be achieved by writing:
<syntaxhighlight lang="raku">
for (0 .. *).map(* ** 2) -> $i {
last if $i > 20;
say $i
}
</syntaxhighlight>
 
However, most of the time custom generators are implemented with "gather" and "take" keywords in a lazy context.
 
===Tcl===
Line 232 ⟶ 240:
===Haskell===
 
In [[Haskell (programming language)|Haskell]], with its [[lazy evaluation]] model, everything is a generator - every datum created with a [[Non-strict evaluation|non-strict]] data constructor is generated on demand. For example,
<syntaxhighlight lang="haskell">
countFrom :: Integer -> [Integer]
countfrom n = n : countfrom (n+1)
countFrom n = n : countFrom (n + 1)
 
from10to20 :: [Integer]
-- Example use: printing out the integers from 10 to 20.
test1from10to20 = mapM_ print $ takeWhile (<= 20) $ countfromcountFrom 10
 
primes = 2 : 3 : nextprime 5 where[Integer]
primes = 2 : 3 : nextPrime 5
nextprime n | b = n : nextprime (n+2)
where
| otherwise = nextprime (n+2)
nextPrime n
where b = all ((/= 0).(rem n)) $ takeWhile ((<= n).(^2)) $ tail primes
| notDivisible n = n : nextPrime (n + 2)
| otherwise = nextPrime (n + 2)
notDivisible n =
all ((/= 0) . (rem n)) $ takeWhile ((<= n) . (^ 2)) $ tail primes
</syntaxhighlight>
where <code>(:)</code> is a non-strict list constructor, ''cons'', and <code>$</code> is just a ''"called-with"'' operator, used for parenthesization. This uses the standard adaptor function,
Line 250 ⟶ 263:
| otherwise = []
</syntaxhighlight>
which re-fetcheswalks valuesdown agreeablethe withlist aand stops on the first element that doesn't satisfy the predicate,. andIf stopsthe requestinglist newhas valuesbeen aswalked soonbefore asuntil athat non-agreeablepoint, oneit is encountered.just Thea sharedstrict storage[[data accessstructure]], isbut usedif asany apart hadn't been walked through before, it will universalbe mediatorgenerated inon Haskelldemand. List comprehensions can be freely used:
<syntaxhighlight lang="haskell">
test2squaresUnder20 = mapM_ print $ takeWhile (<= 20) [x * x | x <- countfromcountFrom 10]
test3squaresForNumbersUnder20 = mapM_ print [x * x | x <- takeWhile (<= 20) $ countfromcountFrom 10]
</syntaxhighlight>
 
Line 284 ⟶ 297:
 
===PHP===
[[File:UML generator in PHP.svg|thumb|UML class diagram depiction of the inheritance chain of the Generator class in PHP]]
The community of PHP implemented generators in PHP 5.5. Details can be found in the original [https://wiki.php.net/rfc/generators RFC about Generator].
The community of [[PHP]] implemented generators in PHP 5.5. Details can be found in the original [https://wiki.php.net/rfc/generators Request for Comments: Generators].
 
Infinite Fibonacci sequence:
<syntaxhighlight lang="php">
function fibonacci(): {Generator
{
$last = 0;
$current = 1;
Line 302 ⟶ 318:
}
</syntaxhighlight>
 
Fibonacci sequence with limit:
<syntaxhighlight lang="php">
function fibonacci(int $limit): Generator
{
yield $a = $b = $i = 1;
while (++$i < $limit) {
yield $a = ($b = $a + $b) - $a;
}
}
 
foreach (fibonacci(10) as $number) {
echo "$number\n";
}
</syntaxhighlight>
 
Any function which contains a <span style="font-family: 'Courier New';">yield</span> statement is automatically a generator function.
 
===Ruby===
Line 322 ⟶ 356:
 
===Java===
Java has had a standard interface for implementing iterators since its early days, and since Java 5, the "foreach" construction makes it easy to loop over objects that provide the <ttcode>java.lang.Iterable</ttcode> interface. (The [[Java collections framework]] and other collections frameworks, typically provide iterators for all collections.)
 
However, [[Java (programming language)|Java]] does not have generators built into the language. This means that creating iterators is often much trickier than in languages with built-in generators, especially when the generation logic is complex. Because all state must be saved and restored every time an item is to be yielded from an iterator, it is not possible to store state in local variables or use built-in looping routines, as when generators are available; instead, all of this must be manually simulated, using object fields to hold local state and loop counters.
 
Even simple iterators built this way tend to be significantly bulkier than those using generators, with a lot of [[boilerplate code]].
 
The original example above could be written in '''Java 7''' as:
<syntaxhighlight lang="java">
// Iterator implemented as anonymous class. This uses generics but doesn't need to.
for (int i: new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int counter = 1;
 
record Pair(int a, int b) {};
@Override
public boolean hasNext() {
return counter <= 100;
}
 
Iterable<Integer> myIterable = Stream.iterate(new Pair(1, 1), p -> new Pair(p.b, p.a + p.b))
@Override
public Integer next.limit(10) {
.map(p -> return counter++p.a)::iterator;
 
}
myIterable.forEach(System.out::println);
 
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}) {
System.out.println(i);
}
</syntaxhighlight>
 
Or get an Iterator from the '''Java 8''' super-interface BaseStream of Stream interface.
An infinite Fibonacci sequence could also be written in '''Java 7''' as an Iterator:
<syntaxhighlight lang="java">
Iterable<Integer> fibo = new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int a = 1, b = 1;
int total;
 
record Pair(int a, int b) {};
@Override
public boolean hasNext() {
return true;
}
 
// Save the iterator of a stream that generates fib sequence
@Override
Iterator<Integer> myGenerator = Stream
public Integer next() {
// Generates Fib total = a + b;sequence
.iterate(new Pair(1, 1), p -> new Pair(p.b, p.a =+ p.b;))
.map(p -> b = totalp.a).iterator();
return total;
}
 
// Print the first 5 elements
@Override
for (int i = 0; i < 5; public void remove(i++) {
System.out.println(myGenerator.next());
throw new UnsupportedOperationException();
}
};
}
};
// this could then be used as...
for (int f: fibo) {
System.out.println("next Fibonacci number is " + f);
if (someCondition(f)) break;
}
</syntaxhighlight>
 
System.out.println("done with first iteration");
Also an infinite Fibonacci sequence could also be written using '''Java 8''' Stream interface:
<syntaxhighlight lang="java">
IntStream.generate(new IntSupplier() {
int a = 1, b = 2;
 
// Print the next 5 elements
public int getAsInt() {
for (int i = 0; i < 5; inti++) temp = a;{
System.out.println(myGenerator.next());
a = b;
}
b = a + temp;
return temp;
}
}).forEach(System.out::println);
</syntaxhighlight>
 
Output:
Or get an Iterator from the '''Java 8''' super-interface BaseStream of Stream interface.
<syntaxhighlight lang="javaconsole">
1
public Iterable<Integer> fibonacci(int limit){
1
return IntStream.generate(new IntSupplier() {
2
int a = 1, b = 2;
3
 
5
public int getAsInt() {
done with first iteration
int temp = a;
8
a = b;
13
b = a + temp;
21
return temp;
34
}
55
}).limit(limit).boxed()::iterator;
}
 
// this could then be used as...
for (int f: fibonacci(10)) {
System.out.println(f);
}
</syntaxhighlight>
 
===C#===
An example C# 2.0 generator (the <code>yield</code> is available since C# version 2.0):
Both of these examples utilize Genericsgenerics, but this is not required. yield keyword also helps in implementing custom stateful iterations over a collection as discussed in this discussion.<ref>{{Cite web|url=https://stackoverflow.com/questions/39476/what-is-the-yield-keyword-used-for-in-ca/15977474#15977474 |title=What is the yield keyword used for in C#?|website=stackoverflow.com|access-date=2018-01-01}}</ref>.
 
<syntaxhighlight lang="csharp">
// Method that takes an iterable input (possibly an array)
// and returns all even numbers.
public static IEnumerable<int> GetEven(IEnumerable<int> numbers)
{
foreach (int inumber in numbers) {
{
if ((inumber % 2) == 0) {
{
yield return inumber;
}
}
Line 447 ⟶ 430:
It is possible to use multiple <code>yield return</code> statements and they are applied in sequence on each iteration:
<syntaxhighlight lang="csharp">
public class CityCollection : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator() {
{
yield return "New York";
yield return "Paris";
Line 476 ⟶ 461:
===F#===
{{further information|Sequence expression}}
[[F Sharp (programming language)|F#]] provides generators via ''[[sequence expression]]s,'' since version 1.9.1.<ref name="seq">{{cite web | url = http://blogs.msdn.com/dsyme/archive/2007/09/22/some-details-on-f-computation-expressions-aka-monadic-or-workflow-syntax.aspx | title = Some Details on F# Computation Expressions | accessdateaccess-date = 2007-12-14}}</ref> These can define a sequence (lazily evaluated, [[sequential access]]) via <code>seq { ... }</code>, a list (eagerly evaluated, sequential access) via <code>[ ... ]</code> or an array (eagerly evaluated, indexed access) via <code>[| ... |]</code> that contain code that generates values. For example,
<syntaxhighlight lang="fsharp">
seq { for b in 0 .. 25 do
Line 486 ⟶ 471:
===Python===
 
Generators were added to [[Python (programming language)|Python]] in version 2.2 in 2001.<ref name="python"/> An example generator:
 
<syntaxhighlight lang="python">
from typing import Iterator
def countfrom(n):
 
def countfrom(n: int) -> Iterator[int]:
while True:
yield n
Line 495 ⟶ 482:
 
# Example use: printing out the integers from 10 to 20.
# Note that this iteration terminates normally, despite
# countfrom() being written as an infinite loop.
 
Line 505 ⟶ 492:
 
# Another generator, which produces prime numbers indefinitely as needed.
import itertools
 
def primes() -> Iterator[int]:
"""Generate prime numbers indefinitely as needed."""
yield 2
n = 3
p = [2]
while True:
# ThisIf worksdividing n by all the numbers in Pythonp, up to and 2.5+including sqrt(n),
if# notproduces any(na %non-zero fremainder ==then 0 for fn inis prime.
if all(n % f > 0 for f in itertools.takewhile(lambda f: f * f <= n, p)):
yield n
p.append(n)
Line 519 ⟶ 508:
</syntaxhighlight>
 
In Python, a generator can be thought of as an [[iterator]] that contains a frozen [[stack frame]]. Whenever the iterator's <code>next()</code> method is called on the iterator, Python resumes the frozen frame, which executes normally until the next <code>yield</code> statement is reached. The generator's frame is then frozen again, and the yielded value is returned to the caller.
 
PEP 380 (implemented in Python 3.3) adds the <ttcode>yield from</ttcode> expression, allowing a generator to delegate part of its operations to another generator or iterable.<ref name="pep380">[https://www.python.org/dev/peps/pep-0380/ PEP 380 -- Syntax for Delegating to a Subgenerator]</ref>
 
====Generator expressions====
 
Python has a syntax modeled on that of [[list comprehension]]s, called a generator expression that aids in the creation of generators.
The following extends the first example above by using a generator expression to compute squares from the <code>countfrom</code> generator function:
<syntaxhighlight lang="python">
squares = (n n* n for n in countfrom(2) )
 
for j in squares:
Line 544 ⟶ 533:
 
<syntaxhighlight lang="javascript">
function* fibonacci(limit) {
// inspired by: http://wiki.ecmascript.org/doku.php?id=harmony:generators
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true!limit || curr <= limit) {
yield curr;
[prev, curr] = [curr, prev + curr];
Line 553 ⟶ 541:
}
 
// bounded by upper limit 10
var gen = fibonacci();
for (const n of fibonacci(10)) {
console.log(gen.next().value); // 1
console.log(gen.next().valuen); // 1
}
console.log(gen.next().value); // 2
 
console.log(gen.next().value); // 3
// generator without an upper bound limit
console.log(gen.next().value); // 5
for (const n of fibonacci()) {
console.log(gen.next().value); // 8
console.log(n);
if (n > 10000) break;
}
 
// manually iterating
let fibGen = fibonacci();
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 2
console.log(fibGen.next().value); // 3
console.log(fibGen.next().value); // 5
console.log(fibGen.next().value); // 8
 
// picks up from where you stopped
for (const n of fibGen) {
console.log(n);
if (n > 10000) break;
}
</syntaxhighlight>
 
===R===
 
The iterators package can be used for this purpose.<ref>http[https://stackoverflow.com/a/16028448/4745348 Generator functions in R]</ref><ref>{{Cite web|url=http://cartesianfaith.wordpress.com/2013/01/05/infinite-generators-in-r/|title=Infinite generators in R|date=5 January 2013}}</ref>
 
<syntaxhighlight lang="r">
Line 573 ⟶ 579:
nextElem(abc)
</syntaxhighlight>
 
===Smalltalk===
 
Example in [[Pharo|Pharo Smalltalk]]:
 
The [[Golden ratio]] generator below returns to each invocation 'goldenRatio next' a better approximation to the Golden Ratio.
 
<syntaxhighlight lang="Smalltalk">
goldenRatio := Generator on: [ :g | | x y z r |
x := 0.
y := 1.
[
z := x + y.
r := (z / y) asFloat.
x := y.
y := z.
g yield: r
] repeat
].
 
goldenRatio next.
</syntaxhighlight>
 
The expression below returns the next 10 approximations.
 
<syntaxhighlight lang="Smalltalk">
Character cr join: ((1 to: 10) collect: [ :dummy | ratio next ]).
</syntaxhighlight>
 
See more in [https://medium.com/concerning-pharo/pharos-hidden-gem-generator-c51ef88aec26 A hidden gem in Pharo: Generator].
 
==See also==
Line 592 ⟶ 628:
 
[[Category:Programming constructs]]
[[Category:Articles with example Python (programming language) code]]
[[Category:Articles with example Haskell code]]
[[Category:Articles with example Ruby code]]
Line 601 ⟶ 637:
[[Category:Articles with example Racket code]]
[[Category:Iteration in programming]]
[[Category:Articles with example R code]]