# Raku feature: Lazy list. This construct will repeat 99 to 0 # and then start over at 99 ad infintum when iterated my @indices = flat (99...0) xx Inf; # for every index, generate the "xx bottles of beer" # when using double quotes the Raku parser interprets # code in curlies as, well, code and embeds the return # value within the string # in the first block we see an ordinary logical or # in the second we see a ternary my @bottles = @indices.map: -> $n { "{$n || 'no more'} bottle{ $n == 1 ?? '' !! 's' } of beer" }; # generate the first line of each verse # Raku also has simple string interpolation my @beers-on-the-wall = @bottles.map: -> $bottles-of-beer { "$bottles-of-beer on the wall, $bottles-of-beer\n".tc }; # Here we see the Z operator at work. It zips together two (or more) lists and returns one value from each. # generate the second line of each verse # Note the deconstruction of the incoming sublist into two variables my @beers-to-get = ( @indices Z @bottles.skip ).map: -> ( $beers-on-the-wall, $beers-available ) { "{ $beers-on-the-wall ?? 'Take one down and pass it around' !! 'Go to the store and buy some more' }, $beers-available on the wall.\n" }; # generate the verses # Here we are not deconstructing the result of the zip operation, so we get a list we can just join my @lyrics = ( @beers-on-the-wall Z @beers-to-get).map: -> @parts { @parts.join } # This is the first time any of the code above actually runs because everything is lazy # Only when we really ask for values the code runs # Here we ask for the first 100 values which is one time the whole song # The ^100 is just a short form to write the range 0..99 .say for @lyrics[ ^100 ]; # Now, here's the kicker. Since the original @indices sequence is infinite we can easily # display the song twice .say for @lyrics[ ^200 ]; # Or even forever .say for @lyrics;