Is it possible to chain metaoperators to calculate the product-sum of two lists in Raku? - operators

I'm learning Raku and something's confusing me.
To calculate the sum of elementwise products of two lists (at least one of them finite) I was hoping to be able to write something like
#a Z*[+] #b
But it doesn't give the expected result.
Using the [+] #a Z* #b form works as expected
> my #a = 2...6;
[2 3 4 5 6]
> my #b = 5...1;
[5 4 3 2 1]
> #a Z #b;
((2 5) (3 4) (4 3) (5 2) (6 1))
> #a Z* #b;
(10 12 12 10 6)
> [+] #a Z* #b
50
But it doesn't like it when I chain the Z* and [+] together
> #a Z*[+] #b
(30)
> #a Z*+ #b
(10)
> #a +Z* #b
===SORRY!=== Error while compiling:
Undeclared name:
Z used at line 1
> #a +[Z*] #b
6
> #a [Z*]+ #b
(10)
> #a [Z*][+] #b
(30)
I imagine there's some precedence issue going on here but don't find adequate examples in the Raku documentation.
I found unexplained behavior with >>*<< as well:
> [+] #a >>*<< #b
50
> #a [+][>>*<<] #b
125
> #a [>>*<<][+] #b
Lists on either side of non-dwimmy hyperop of infix:<*> are not of the same length while recursing
left: 5 elements, right: 1 elements
in block <unit> at <unknown file> line 1
Questions
Is it possible to evaluate the product-sum of two lists in this way?
What's happening across the different chained variants to cause results like 6, (10), (30) and 125?

Is it possible to evaluate the product-sum of two lists in this way?
Yes.
Let's start with chaining:
One can write Raku code that chains right-to-left but we'll stick with left-to-right.
A left to right English reading of what you're calling "product sum" would be "sum of products of elements of these lists". So we want sum on left, product next, lists last.
There is a built in sum but no built in product, so we need to deal with the latter. One way is to write [Z*] as a reduction (which means it has to appear on the left of the lists it reduces over). Another is to write a new product function.
Putting the above together, here are some of the ways we can write a "product sum":
say [+] [Z*] #a, #b; # 50 (closest to what it seems you want)
say sum [Z*] #a, #b; # 50 (`sum` is idiomatic)
say sum zip :with(&[*]), #a, #b; # 50 (some prefer `zip :with(&[*])` over `[Z*]`)
say sum product #a, #b; # 50 (requires a user defined `sub`)
sub product (|lists) { zip :with(&[*]), |lists }
Doing it as above means you can use any number of lists rather than just two.
If you really want to stick with infix notation, which limits you to two lists, you can do that for the product part:
say [+] #a Z* #b; # 50 (using infix sequential shallow zip metaop)
say [+] #a >>*<< #b; # 50 (using infix parallel nesting hyper metaop)
say sum #a Z* #b; # 50 (replacing `sum` with `[+]` reduction)
say sum #a >>*<< #b; # 50
What's happening across the different chained variants to cause results like 6, (10), (30) and 125?
Raku is correctly doing what your code expresses.
The following code examples explain all the code/results #Zaid shared. You (any reader, not just #Zaid) may have to do some work to understand why; if you can't work out how these examples explain one or more of Zaid's results, please comment and I'll be happy to explain in a comment and/or update this answer and will thank you for your question/comment.
say my #a = 2...6; # [2 3 4 5 6]
say my #b = 5...1; # [5 4 3 2 1]
say [+] [5,4,3,2,1]; # 15
# Same as:
say sum #b; # 15
say 2 Z* 15; # (30)
# zip stops once shortest list exhausted, so same as:
say [2,3,4,5,6] Z* 15; # (30)
say +#b; # 5
# `+` coerces argument(s) to number, so short for:
say elems #b; # 5
# Same as:
say elems [5,4,3,2,1]; # 5
say 2 Z* 5; # (10)
#say +foo; # Error while compiling: Undeclared ... foo
# Same effect as:
#say foo; # Error while compiling: Undeclared ... foo
say [Z*] #b; # (120)
# Same as:
say 5 Z* 4 Z* 3 Z* 2 Z* 1; # (120)
say #a [Z*] 5; # (10)
# square brackets redundant, and
# zip stops once shortest list exhausted, so same as:
say 2 Z* 5; # (10)
say [+] #a >>*<< #b; # 50
say [>>*<<] #b; # 120
# hypers redundant if both args scalars, so same as:
say [*] [5,4,3,2,1]; # 120
# (5 * 4 * 3 * 2 * 1)
say #a [+] [>>*<<] #b; # 125
# square brackets round infix `+` redundant, so same as:
say #a + [>>*<<] #b; # 125
# hypers redundant if both args scalars, so same as:
say 5 + [*] #b; # 125 (5 + 120)
say #a [>>*<<][+] #b; # Same as:
say #a [>>*<<] [+] #b; #
say #a [>>*<<] sum #b; #
say #a >>*<< sum #b; #
#say #a >>*<< 15; # Lists on either side ... not of the same length

Related

How to divide every element in array by a certain number?

I have an array:
my #e = <60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725>
I would like to divide every element in the array by the minimum, however
#e /= #e.min
produced a single element, which isn't correct.
I've read https://docs.raku.org/type/Array but I don't understand the basic elements of Raku for this.
How can I divide every item in the array by the same number?
You can use the raku hyper & compound metaoperators like this:
#a >>/=>> #a.min
>>X>> means "apply operator X over all list items (with more items on the left)"
/= means "assign result of divide operator / to replace each original left hand item"
Use / instead of /= if you want to return the list of results but leave #a unchanged functional programming style.
[Edited according to #lizmat & #Sebastian comments]
my #a = 2, 3, 5, 7, 10;
my $div = #a.min;
$_ /= $div for #a;
say #a; # [1 1.5 2.5 3.5 5]
When you iterate over an array, you get mutable elements.
put #e.map( * / #e.min );
OR
put #e.map: * / #e.min;
Sample Input:
my #e = <60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725>;
Sample Output:
22.356697 7.686606 3.200367 2.675963 1.580183 1.035229 1.014679 1.009908 1.005872 1
If you want to continue working with the resultant values, assign the output to a new variable. Or overwrite the original #e array using the .= "back-assignment" operator [ short for #e = #e.map( … ) ]. In the Raku REPL:
~$ raku
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.06.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.06.
To exit type 'exit' or '^D'
> my #e = <60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725>;
[60.922 20.946 8.721 7.292 4.306 2.821 2.765 2.752 2.741 2.725]
> #e .= map( * / #e.min );
[22.356697 7.686606 3.200367 2.675963 1.580183 1.035229 1.014679 1.009908 1.005872 1]
> put #e;
22.356697 7.686606 3.200367 2.675963 1.580183 1.035229 1.014679 1.009908 1.005872 1
>

Avoid creating temporary scalars when returning multiple arrays

Is it possible to avoid creating temporary scalars when returning multiple arrays from a function:
use v6;
sub func() {
my #a = 1..3;
my #b = 5..10;
return #a, #b;
}
my ($x, $y) = func();
my #x := $x;
my #y := $y;
say "x: ", #x; # OUTPUT: x: [1 2 3]
say "y: ", #y; # OUTPUT: y: [5 6 7 8 9 10]
I would like to avoid creating the temporary variables $x and $y.
Note: It is not possible to replace the function call with
my (#x, #y) = func()
since assignment of a list to an Array is eager and therefore both the returned arrays end up in #x.
Not either of:
my ($x, $y) = func();
my (#x, #y) = func();
But instead either of:
my (#x, #y) := func();
my ($x, $y) := func();
Use # to signal to P6 that, when it needs to distinguish whether something is singular -- "a single array" -- or plural -- "items contained in a single array" -- it should be treated as plural.
Use $ to signal the other way around -- it should be treated as singular.
You can always later explicitly reverse this by doing $#x -- to signal P6 should use the singular perspective for something you originally declared as plural -- or #$x to signal reversing the other way around.
For an analogy, think of a cake cut into several pieces. Is it a single thing or a bunch of pieces? Note also that # caches indexing of the pieces whereas $ just remembers that it's a cake. For large lists of things this can make a big difference.

Map signature mismatch with Whatever? x vs X vs xx

The last line here results in a incorrect signature to the map call:
my #array=[0,1,2];
say "String Repetition";
say #array.map({($_ x 2)});
say #array.map: * x 2;
say "\nCross product ";
say #array.map({($_ X 2)});
say #array.map: * X 2;
say "\nList Repetition";
say #array.map({$_ xx 2});
say #array.map: * xx 2;
The output being:
String Repetition
(00 11 22)
(00 11 22)
Cross product
(((0 2)) ((1 2)) ((2 2)))
(((0 2)) ((1 2)) ((2 2)))
List Repetition
((0 0) (1 1) (2 2))
Cannot resolve caller map(Array:D: Seq:D); none of these signatures match:
($: Hash \h, *%_)
(\SELF: &block;; :$label, :$item, *%_)
The x operator returns a Str, the X returns a List of Lists and the xx return a List.
Is this changed somehow using the Whatever. Why is this error happening? Thanks in advance
Let me see if I can get this through clearly. If I don't, please ask.
Short answer: xx has a special meaning together with Whatever, so it's not creating a WhateverCode as in the rest of the examples.
Let's see if I can get this straight with the long answer.
First, definitions. * is called Whatever. It's generally used in situations in which it's curried
I'm not too happy with this name, which points at functional-language-currying, but does not seem to be used in that sense, but in the sense of stewing or baking. Anyway.
Currying it turns it into WhateverCode. So an * by itself is Whatever, * with some stuff is WhateverCode, creating a block out of thin air.
However, that does not happen automatically, because some times we need Whatever just be Whatever. You have a few exceptions listed on Whatever documentation. One of them is using xx, because xx together with Whatever should create infinite lists.
But that's not what I'm doing, you can say. * is in front of the number to multiply. Well, yes. But this code in Actions.nqp (which generates code from the source) refers to infix xx. So it does not really matter.
So, back to the short answer: you can't always use * together with other elements to create code. Some operators, such as that one, .. or ... will have special meaning in the proximity of *, so you'll need to use something else, like placeholder arguments.
The xx operator is “thunky”.
say( rand xx 2 );
# (0.7080396712923503 0.3938678220039854)
Notice that rand got executed twice. x and X don't do that.
say( rand x 2 );
0.133525574759261740.13352557475926174
say( rand X 1,2 );
((0.2969453468495996 1) (0.2969453468495996 2))
That is xx sees each side as something sort of like a lambda on their own.
(A “thunk”)
say (* + 1 xx 2);
# ({ ... } { ... })
say (* + 1 xx 2)».(5);
# (6 6)
So you get a sequence of * repeated twice.
say (* xx 2).map: {.^name}
# (Whatever Whatever)
(The term *, is an instance of Whatever)
This also means that you can't create a WhateverCode closure with && / and, || / or, ^^ / xor, or //.
say (* && 1);
# 1
Note that * also does something different on the right side of xx.
It creates an infinite sequence.
say ( 2 xx * ).head(20);
# (2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2)
If xx wasn't “thunky”, then this would also have created a WhateverCode lambda.

Retrieving data from a hash with array values in Perl 6

I have an array of 3 elements:
my #a = <x y z>;
Then I make a hash with Array values and make #a's contents one of its values:
my Array %h;
%h<a> = #a;
Later I retrieve this value and assign it to another array:
my #A = %h<a>;
But what I get in #A is not an array of 3 elements, but an array of one element, which is itself an array of 3 elements:
say #A; # [[x y z]]
say #A[0].elems; # 3
So, %h<a> was pushed into #A.
Where is the error in my code?
UPD: This seems to fix the problem, but doesn't improve my understanding. :)
my #A = #(%h<a>);
say #A; [x y z]
The reason this happens, is that the array #a must be put into a container to allow to be stored as a value in a Hash. And something inside a container will remain in the container when being stored into array #A. So, what you need is to get rid of the container when you assign to #A. Your solution is one way of getting rid of the container, but that creates an intermediate List, which could become expensive for large arrays.
As I said, you need to get rid of the container. Fortunately, we have a syntax for that: postfix <>:
my #a = <a b c>;
my %h = a => #a;
my #b = %h<a><>; # <-- note the <> here
dd #b; # Array #b = ["a", "b", "c"]
This would be the most efficient way if you really want #b to be mutable. Alternately, if you want #b to be just an alias of the original #a, you could also bind:
my #a = <a b c>;
my %h = a => #a;
my #b := %h<a>; # <-- note the := here
dd #b; # Array #a = ["a", "b", "c"]
Note that the dd output now shows #a as the name, as it now really is the same as #a: any changes to #a will now also show in #b and vice-versa. Which would be ok if you're not changing them anyway. If that's true in your situation, then this would be the most efficient way of doing this, both CPU-wise as well as memory-wise.

How to calculate alternating sum of digits of an integer in Perl 6?

A number is divisible by 11 if its alternating sum of digits is
divisible by 11.
So, e.g. if number is 1595, +1 -5 +9 -5 == 0, so 1595 is divisible by 11. How to implement such a sum? Here is my solution, but it's too complex and works only if the number of digits is even.
my $number = 1595;
say [+] $number.comb.map({$^a - $^b});
What's the best way to do it?
say [+] 1595.comb Z* (1, -1, 1 ... *)
To break it down: .comb returns a list of characters, and Z* multiplies that list element-wise with the sequence on the RHS.
This sequence is a geometric sequence, which the ... series operator can deduce from the three elements. Since the zip operator Z stops at the shortest sequence, we don't have to take care to terminate the sequence on the RHS.
Another way to write the same thing is:
say [+] 1595.comb Z* (1, -* ... *)
Where -* is the explicit negation of the previous value, applied to the initial element to generate the next one.
You could also write that as
say [+] 1595.comb Z* (1, &prefix:<-> ... *)
The cross that Moritz uses is interesting (and quite pleasing) but you can also take chunks of a list. This is close to what you were trying initially. I think you were going toward rotor:
my $number = 1595;
say [+] $number.comb.rotor(2, :partial).map: { $^a.[0] - ($^a.[1] // 0) }
Notice that you get one argument to your block. That's the list. It's a bit ugly because the odd digit case makes $^a.[1] Nil which would give a warning.
Now that I've played with this a bit more I handle that with a signature so I can give $b a default. This is much better:
my $number = 1595;
say [+] $number
.comb
.rotor(2, :partial)
.map: -> ( $a, $b = 0 ) { $a - $b }
But you don't even need the rotor because the map will grab as many positional parameters as it needs (h/t to timotimo in the comments). This means you were really close and merely missed the signature:
my $number = 1595;
say [+] $number
.comb
.map: -> ( $a, $b = 0 ) { $a - $b }
The solution you have in the comment doesn't quite work for the odd number of digits cases:
say [+] $number.comb.rotor(2, :partial).map({[-] $_});
And, I know this problem wasn't really about divisors but I'm quite pleased that Perl 6 has a "divisible by" operator, the %%:
$ perl6
> 121 %% 11
True
> 122 %% 11
False
> 1595 %% 11
True
> 1596 %% 11
False
say [+] 1595.comb >>*>> (1,-1)
Similar to the Z* version but using the hyper meta operator looping effect on the right hand side (if the left hand side has less than 2 digits you are fine).
Here's my solution.
say [+] 15956.comb.kv.map( (-1) ** * * * ); # 6
And a more explicit version.
say [+] 15956.comb.kv.map({ $^b * (-1) ** $^a }); # 6
UPD: Yet another solution.
say - [+] 15956.comb(2)>>.comb.map({[R-] $_}); # 6