Home > Raku > Only infinite elements

## 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;``

Categories: Raku
1. August 3, 2021 at 21:57

I can only wonder what the optimizer makes of this, but it works:

[+] .head( .first: * <= 2, :k ) with cache (1..6).pick xx *

1. August 2, 2021 at 20:32