Content deleted Content added
→Timeline: ES6/ES2015/Harmony became an official standard over a year ago. Now, there's also ES2016 |
m <syntaxhighlight>; <pre> for unsupported lang |
||
Line 50:
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 | accessdate = <!-- 24 May 2013 --> | doi = 10.1145/359763.359789 }}</ref>
<
string_chars = iter (s: string) yields (char);
index: int := 1;
Line 63:
...
end;
</syntaxhighlight>
===Icon===
Line 70:
Printing squares from 0 to 20 can be achieved using a co-routine by writing:
<pre>
local squares, j
squares := create (seq(0) ^ 2)
Line 78:
else
break
</
However, most of the time custom generators are implemented with the "suspend" keyword which functions exactly like the "yield" keyword in CLU.
Line 86:
It is possible to introduce generators into C++ using pre-processor macros. The resulting code might have aspects very different from native C++. but the generator syntax can be very uncluttered. A very good example can be found at.<ref>http://www.codeproject.com/KB/cpp/cpp_generators.aspx</ref> The set of pre-processor macros defined in this source allow generators defined with the syntax as in the following example:
<
$generator(descent)
{
Line 103:
$stop; // stop, end of sequence. End of body of the generator.
};
</syntaxhighlight>
This can then be iterated using:
<
int main(int argc, char* argv[])
{
Line 115:
return 0;
}
</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:
<
#include <iostream>
int main()
Line 129:
return 0;
}
</syntaxhighlight>
A basic range implementation would look like that:
<
class range
{
Line 155:
int operator*() const { return iter; }
};
</syntaxhighlight>
===Perl===
Line 161:
Perl does not natively provide generators, but support is provided by the [https://metacpan.org/module/Coro::Generator Coro::Generator] module which uses the [https://metacpan.org/module/Coro Coro] co-routine framework. Example usage:
<
use strict;
use warnings;
Line 181:
print $letters->(), "\n" for (0..15);
</syntaxhighlight>
===Tcl===
Line 187:
In [[Tcl]] 8.6, the generator mechanism is founded on named [[coroutine]]s.
<
proc generator {body} {
coroutine gen[incr ::disambiguator] apply {{script} {
Line 210:
puts [$count]
}
</syntaxhighlight>
===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,
<
countfrom n = n : countfrom (n+1)
Line 225:
| otherwise = nextprime (n+2)
where b = 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,
<
takeWhile p [] = []
takeWhile p (x:xs) | p x = x : takeWhile p xs
| otherwise = []
</syntaxhighlight>
which re-fetches values agreeable with a predicate, and stops requesting new values as soon as a non-agreeable one is encountered. The shared storage access is used as a universal mediator in Haskell. List comprehensions can be freely used:
<
test2 = mapM_ print $ takeWhile (<= 20) [x*x | x <- countfrom 10]
test3 = mapM_ print [x*x | x <- takeWhile (<= 20) $ countfrom 10]
</syntaxhighlight>
===Racket===
[[Racket (programming language)|Racket]] provides several related facilities for generators. First, its for-loop forms work with ''sequences'', which are a kind of a producer:
<
(for ([i (in-range 10 20)])
(printf "i = ~s\n" i))
</syntaxhighlight>
and these sequences are also first-class values:
<
(define 10-to-20 (in-range 10 20))
(for ([i 10-to-20])
(printf "i = ~s\n" i))
</syntaxhighlight>
Some sequences are implemented imperatively (with private state variables) and some are implemented as (possibly infinite) lazy lists. Also, new struct definitions can have a property that specifies how they can be used as sequences.
But more directly, Racket comes with a generator library for a more traditional generator specification. For example,
<
#lang racket
(require racket/generator)
Line 262:
(define g (ints-from 10))
(list (g) (g) (g)) ; -> '(10 11 12)
</syntaxhighlight>
Note that the Racket core implements powerful continuation features, providing general (re-entrant) continuations that are composable, and also delimited continuations. Using this, the generator library is implemented in Racket.
Line 268:
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].
<
function fibonacci() {
$last = 0;
Line 283:
echo $number, "\n";
}
</syntaxhighlight>
===Ruby===
Ruby supports generators (starting from version 1.9) in the form of the built-in Enumerator class.
<
# Generator from an Enumerator object
chars = Enumerator.new(['A', 'B', 'C', 'Z'])
Line 301:
100.times { puts count.next }
</syntaxhighlight>
===Java===
Line 311:
The original example above could be written in '''Java 7''' as:
<
// Iterator implemented as anonymous class. This uses generics but doesn't need to.
for (int i: new Iterable<Integer>() {
Line 338:
System.out.println(i);
}
</syntaxhighlight>
An infinite Fibonacci sequence could also be written int '''Java 7''' as an Iterator:
<
Iterable<Integer> fibo = new Iterable<Integer>() {
@Override
Line 374:
if (someCondition(f)) break;
}
</syntaxhighlight>
Also an infinite Fibonacci sequence could also be written using '''java 8''' Stream interface:
<
Stream.generate(new Supplier<Integer>() {
int a = 1, b = 2;
Line 388:
}
}).forEach(System.out::print);
</syntaxhighlight>
Or get an Iterator from the '''Java 8''' super-interface BaseStream of Stream interface.
<
public Iterable<Integer> fibonacci(int limit){
return ()->{
Line 411:
System.out.println(f);
}
</syntaxhighlight>
===C#===
Line 417:
Both of these examples utilise Generics, but this is not required.
<
// Method that takes an iterable input (possibly an array)
// and returns all even numbers.
Line 427:
}
}
</syntaxhighlight>
It is possible to use multiple <code>yield return</code> statements and they are applied in sequence on each iteration:
<
public class CityCollection : IEnumerable<string> {
public IEnumerator<string> GetEnumerator() {
Line 438:
}
}
</syntaxhighlight>
===XL===
In [[XL (programming language)|XL]], iterators are the basis of 'for' loops:
<
import IO = XL.UI.CONSOLE
Line 456:
for I in 1..5 loop
IO.WriteLn "I=", I
</syntaxhighlight>
===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 | accessdate = 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,
<
seq { for b in 0 .. 25 do
if b < 15 then
yield b * b }
</syntaxhighlight>
forms a sequence of squares of numbers from 0 to 14 by filtering out numbers from the range of numbers from 0 to 25.
Line 472:
Generators were added to [[Python (programming language)|Python]] in version 2.2.<ref name="python"/> An example generator:
<
def countfrom(n):
while True:
Line 501:
p.append(n)
n += 2
</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, 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.
Line 511:
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 example above by using a generator expression to compute squares from the countfrom generator function:
<
squares = ( n*n for n in countfrom(2) )
Line 519:
else:
break
</syntaxhighlight>
===ECMAScript===
Line 527:
An infinite Fibonacci sequence can be written using a function generator:
<
// inspired by: http://wiki.ecmascript.org/doku.php?id=harmony:generators
function* fibonacci() {
Line 544:
console.log(gen.next().value); // 5
console.log(gen.next().value); // 8
</syntaxhighlight>
===R===
Line 550:
The iterators package can be used for this purpose.<ref>{{cite web|url=http://stackoverflow.com/a/16028448/4745348}}</ref>
<
# See http://stackoverflow.com/a/16028448/4745348 and http://cartesianfaith.wordpress.com/2013/01/05/infinite-generators-in-r/
Line 558:
abc <- iter(c('a','b','c'))
nextElem(abc)
</syntaxhighlight>
==See also==
|