Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map signature mismatch with Whatever? x vs X vs xx

Tags:

raku

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: █; :$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

like image 666
drclaw Avatar asked Mar 03 '19 04:03

drclaw


2 Answers

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.

like image 63
jjmerelo Avatar answered Oct 22 '22 05:10

jjmerelo


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.

like image 26
Brad Gilbert Avatar answered Oct 22 '22 04:10

Brad Gilbert