List comprehensions: Difference between revisions

no edit summary
m (→‎{{header|Sidef}}: Fix link: Perl 6 --> Raku)
No edit summary
Line 2,169:
[9,12,15]
[12,16,20]</pre>
 
 
=={{header|Rust}}==
 
Rust doesn't have comprehension-syntax, but it has powerful lazy-iteration mechanisms topped with a powerful macro system, as such you can implement comprehensions on top of the language fairly easily.
 
=== Iterator ===
 
First using the built-in iterator trait, we can simply flat-map and then filter-map:
 
<lang rust>fn pyth(n: u32) -> impl Iterator<Item = [u32; 3]> {
(1..=n).flat_map(move |x| {
(x..=n).flat_map(move |y| {
(y..=n).filter_map(move |z| {
if x.pow(2) + y.pow(2) == z.pow(2) {
Some([x, y, z])
} else {
None
}
})
})
})
}</lang>
 
* Using <code>flat_map</code> we can map and flatten an iterator.
 
* Use <code>filter_map</code> we can return an <code>Option</code> where <code>Some(value)</code> is returned or <code>None</code> isn't. Technically we could also use <code>flat_map</code> instead, because <code>Option</code> implements <code>IntoIterator</code>.
 
* Using the <code>impl Trait</code> syntax, we return the <code>Iterator</code> generically, because it's statically known.
 
* Using the <code>move</code> syntax on the closure, means the closure will take ownership of the values (copying them) which is what we wan't because the captured variables will be returned multiple times.
 
=== Comprehension Macro ===
 
Using the above and <code>macro_rules!</code> we can implement comprehension with a reasonably sized macro:
 
<lang rust>macro_rules! comp {
($e:expr, for $x:pat in $xs:expr $(, if $c:expr)?) => {{
$xs.filter_map(move |$x| if $($c &&)? true { Some($e) } else { None })
}};
($e:expr, for $x:pat in $xs:expr $(, for $y:pat in $ys:expr)+ $(, if $c:expr)?) => {{
$xs.flat_map(move |$x| comp!($e, $(for $y in $ys),+ $(, if $c)?))
}};
}</lang>
 
The way to understand a Rust macro is it's a bit like regular expressions. The input matches a type of token, and expands it into the block, for example take the follow pattern:
 
<lang rust>($e:expr, for $x:pat in $xs:expr $(, if $c:expr)?)</lang>
 
# matches an <code>expr</code> expression, defines it to <code>$e</code>
# matches the tokens <code>, for</code>
# matches a <code>pat</code> pattern, defines it to <code>$x</code>
# matches the tokens <code>in</code>
# matches an <code>expr</code> expression, defines it to <code>$xs</code>
# matches <code>$(..)?</code> optional group
## patches tokens <code>, if</code>
## matches an <code>expr</code> expression, defines it to <code>$c</code>
 
This makes the two following blocks equivalent:
 
<lang rust>comp!(x, for x in 0..10, if x != 5)</lang>
 
<lang rust>(0..10).filter_map(move |x| {
if x != 5 && true {
Some(x)
} else {
None
}
})</lang>
 
The most interesting part of <code>comp!</code> is that it's a recursive macro (it expands within itself), and that means it can handle any number of iterators as inputs.
 
=== Iterator Comprehension ===
 
The pythagorean function could as such be defined as the following:
 
<lang rust>fn pyth(n: u32) -> impl Iterator<Item = [u32; 3]> {
comp!(
[x, y, z],
for x in 1..=n,
for y in x..=n,
for z in y..=n,
if x.pow(2) + y.pow(2) == z.pow(2)
)
}</lang>
 
 
=={{header|Scala}}==
Anonymous user