Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question on the array generating sequence in Raku

I've come across this code at rosettacode

my @pascal = [1], { [0, |$_ Z+ |$_, 0] } ... Inf;
.say for @pascal[^4];
# ==>
# [1]
# [1 1]
# [1 2 1]
# [1 3 3 1]

Inside the explicit generator block, I know how the individual operators like the list flattening | and the zip operator Z+ work but I have difficulty comprehending how they cooperate to generate the next array. Can somebody explain in detail how it works? Thank you.

Note: The code is slightly rearranged for brevity, i.e. it's superficially different than the one in Rosetta.

like image 801
Lars Malmsteen Avatar asked Nov 21 '19 14:11

Lars Malmsteen


2 Answers

So let's take a look at what's going on.

First up the Sequence generator ... this takes a list of starting values, a code block itself and and end point.

It uses the starting values to generate each next item in the list so lets start with @pascal[0] that's simple enough : [1]

For @pascal[1] we call the code block with our value in @pascal[0] like so :

sub ( $array ) { 
  [0, |$array Z+ |$array, 0] 
}

You'll note I've made it into a sub, this is just so I can explain things easier. In the anonymous code block $_ is the incoming data and I've called it $array. So what code to we run when $array == [1]?

[0, |[1] Z+ |[1], 0] => [1,1] 

So here's a question what happens if we don't use the | ?

[0, [1] Z+ [1], 0] => [1,1] 

It's the same! So whys it there? Well what happens if we set $array == [3]?

[0, [3] Z+ [3], 0] => [1,1] 

Weird? No, because the Z+ transforms like this :

[0, [3] Z+ [3], 0] => [0 + [3], [3] + 0] => [1,1] 

Z makes a new list by zipping the elements with the given operator + between them. + is doing a numerical computation and the Numerical representation of an Array is the number of elements in it, in this case 1 both times.

And this is where the | slip operator comes in, it slips the array it's given open merging into the list context it's in. So lets go back to @pascal[1]

[0, |[1] Z+ |[1], 0] => [0, 1 Z+ 1, 0] => [0 + 1, 1 + 0] => [1,1] 

Ok.. So @pascal[2] is calling the same block but now passing in [1,1]

[0, |[1, 1] Z+ |[1, 1], 0] => [0, 1, 1 Z+ 1, 1, 0] => [0 + 1, 1 + 1, 1 + 0] => [1,2,1] 

And so on into Infinity!

I hope that's helped to explain what's going on?

like image 186
Scimon Proctor Avatar answered Dec 27 '22 23:12

Scimon Proctor


This is a somewhat interesting application of the sequence operator, in so far as the values that it produces each time are arrays. So:

  • [1] is the first array produced at the start of the sequence
  • The block indicates how to produce the next array in the sequence. It takes one argument, which is the previous sequence value
  • The Inf will never be matched, so the sequence will go on forever

A simpler example may be helpful: the sequence [1], [1,1], [1,1,1], .... That is, we want to produce an array that is the previous item in the sequence with an extra 1 at the end. We could do this:

my @ones = [1], { [|$_, 1] } ... Inf;
.say for @ones[^4];

Producing:

[1]
[1 1]
[1 1 1]
[1 1 1 1]

The first time the block is called, it gets [1] in $_. We slip that with |, thus producing an array [1, 1]. That is passed to the block the second time, and so forth.

So, breaking down [0, |$_ Z+ |$_, 0]. The outer square brackets are an array composer. The rest can be read as 0, |$_ zipped with |$_, 0, using the + operator to zip the things.

The first call to be block will pass [1], thus we will be zipping 0, 1 and 1, 0. Zipping with an operator applies it pairwise, meaning it will calculate 0 + 1, 1 + 0. The overall result is the array [1,1].

The second call to the block gets that [1,1]. It forms the lists 0, 1, 1 and 1, 1, 0, and then the zip operator forms the pairwise addition again, which is 0 + 1, 1 + 1, 1 + 0. The overall result is the array [1,2,1].

Effectively, then, the result grows an element each time, resulting from the pairwise addition of the previous result padded with a zero at either end.

like image 41
Jonathan Worthington Avatar answered Dec 27 '22 23:12

Jonathan Worthington