Only infinite elements
Flavio solved a puzzle with an implementation that puzzled me. The following code appears not as idiomatic as such a simple problem should require.
sub simulation-round () {
return [+] gather {
loop {
my $value = roll-die();
take $value;
last if $value < 3;
}
}
}
We tend to do our dice rolls with a simpler construct.
sub simulation-round () {
[+] (1..6).roll(*).map({ last .Int if .Int < 3; .Int });
}
# OUTPUT: Cannot .sum a lazy list onto a Seq
# in sub simulation-round at ETOOBUSY-2.raku line 4
# in block <unit> at ETOOBUSY-2.raku line 7
Rakudo assumes that a lazy list must be infinite. This would catch many bugs but is not what I want in this case. Sadly we don’t have a build-in to say .lazy-but-finite
. Neither do we got roles we could mixin. This might be the reason why it took me 10 minutes of staring‑at‑the‑code to find a solution.
[+] (1..6).roll(*).map({ last if .Int < 3; .Int })[^∞]
So we are asking for up to infinite elements of this infinite list to defuse the laziness. This smells of bad design and may warrant a problem solving issue.
The rest of my version is quite different because I wanted to shoehorn a .hyper
in.
use v6.*;
unit sub MAIN($rounds = 1_000_000);
sub term:<🎲>() { (1..6).roll(*) };
sub simulation-round () {
[+] 🎲.map({ last .Int if .Int < 3; .Int })[^∞];
}
my $total = (0..^$rounds).hyper(:degree(12), :batch(10000)).map({ simulation-round }).sum;
put ‚average gain: ‘, $total / $rounds;
I believe there is a life‑lesson to be learned. Laziness can be problematic if the compiler is less then virtuos.
UPDATE:
As lizmat pointed out, last .Int
requires v6.e.PREVIEW
(v6.*
will work too). Instead of [^∞]
a simple .eager
will do (but will break the title of the blog post). We can also use ^$rounds
instead of (0..^$rounds)
if we disambiguate with a space before the method call.
my $total = ^$rounds .hyper(:degree(12), :batch(10000)).map({ simulation-round }).sum;
I can only wonder what the optimizer makes of this, but it works:
[+] .head( .first: * <= 2, :k ) with cache (1..6).pick xx *