Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Questions on the prime number calculating code in Raku

I've come across this code at RosettaCode

constant @primes = 2, 3, { first * %% none(@_), (@_[* - 1], * + 2 ... Inf) } ... Inf;
say @primes[^10];

Inside the explicit generator block:

1- What or which sequence do the @_ s refer to?

2- What does the first * refer to?

3- What do the * in @_[* - 1] and the next * refer to?

4- How does the sequence (@_[* - 1], * + 2 ... Inf) serve the purpose of finding prime numbers?

Thank you.

like image 863
Lars Malmsteen Avatar asked Nov 13 '19 16:11

Lars Malmsteen


1 Answers

The outer sequence operator can be understood as: start the sequence with 2 and 3, then run the code in the block to work out each of the following values, and keep going until infinity.

The sequence operator will pass that block as many arguments as it asks for. For example, the Fibonacci sequence is expressed as 1, 1, * + * ... Inf, where * + * is shorthand for a lambda -> $a, $b { $a + $b }; since this wishes for two parameters, it will be given the previous two values in the sequence.

When we use @_ in a block, it's as if we write a lambda like -> *@_ { }, which is a slurpy. When used with ..., it means that we wish to be passed all the previous values in the sequence.

The sub first takes a predicate (something we evaluate that returns true or false) and a list of values to search, and returns the first value matching the predicate. (Tip for reading things like this: whenever we do a call like function-name arg1, arg2 then we are always parsing a term for the argument, meaning that we know the * cannot be a multiplication operator here.)

The predicate we give to first is * %% none(@_). This is a closure that takes one argument and checks that it is divisible by none of the previous values in the sequence - for if it were, it could not be a prime number!

What follows, @_[* - 1], * + 2 ... Inf, is the sequence of values to search through until we find the next prime. This takes the form: first value, how to get the next value, and to keep going until infinity.

The first value is the last prime that we found. Once again, * - 1 is a closure that takes an argument and subtracts 1 from it. When we pass code to an array indexer, it is invoked with the number of elements. Thus @arr[* - 1] is the Raku idiom for "the last thing in the array", @arr[* - 2] would be "the second to last thing in the array", etc.

The * + 2 calculates the next value in the sequence, and is a closure that takes an argument and adds 2 to it. While we could in fact just do a simple range @_[* - 1] .. Inf and get a correct result, it's wasteful to check all the even numbers, thus the * + 2 is there to produce a sequence of odd numbers.

So, intuitively, this all means: the next prime is the first (odd) value that none of the previous primes divide into.

like image 113
Jonathan Worthington Avatar answered Nov 13 '22 15:11

Jonathan Worthington