Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WhateverStar `&&` WhateverStar in Perl 6

Tags:

raku

* > 20 && * %% 5 used in grep seems wrong, does is equal to a WhateverCode lambda that takes 2 arguments? As this explain on SO

> my @a = 1,12,15,20,25,30,35,37;

> @a.grep: * > 20 && * %% 5 # The result seems strange, expected (25 30 35)
(15 20 25 30 35)

> @a.grep: * %% 5 && * > 20
(25 30 35 37)

> @a.grep: { $_>20 && $_ %% 5 }
(25 30 35)

> @a.grep: all(* > 20, * %% 5)
(25 30 35)

> @a.grep: -> $a { all($a > 20, $a %% 5) }
(25 30 35)

> @a.grep: -> $a {$a > 20 && $a %% 5}
(25 30 35)
like image 773
chenyf Avatar asked May 10 '18 12:05

chenyf


2 Answers

Golfed

my &or  = * == 1 || * == 2 ;
my &and = * == 1 && * == 2 ;

say .signature, .(1), .(2)
  for &or, ∧

displays:

(;; $whatevercode_arg_1 is raw)TrueFalse
(;; $whatevercode_arg_4 is raw)FalseTrue

I still don't know what's going on [ed: that is, I didn't at the time I wrote this paragraph; I kept what I wrote in this answer as the mystery unfolded], but it's clear that the signature is for just one arg and the result is as per just the right hand expression for the &and and the left hand for the &or which means the code doesn't seem to have, er, left the result that's, er, right. Investigation continues... (and no, I'm not det remiker).

Mystery solved

So, it looks like the logical ops (&&, ||, and, or, etc.) don't do Whatever-currying. Which is fair enough given that "not all operators and syntactic constructs curry * (or Whatever-stars) to WhateverCode". Logical, even, given their nature. They probably ought to be added to the table of exceptions on that page though.

In the meantime, operators like == do Whatever curry. Again, that's fair enough given "subexpressions may impose their own Whatever star rules".

So it makes sense that &or and &and turn in to...

Aha! Got it. The * == 1 and * == 2 are evaluated at compile-time and turn into WhateverCodes. As WhateverCodes they are just bits of code. They are defined. They are True. (This ignores calling them at run-time.) Then along comes the && and evaluates to the right hand WhateverCode. (The || would evaluate to its left hand WhateverCode.)

Hence the behavior we see.

A solution

Per prompting by @HåkonHægland, the code that would work is therefore code that doesn't rely on logical ops Whatever-currying, i.e.:

my @a = 1,12,15,20,25,30,35,37;

say @a.grep: { $_ > 20 && $_ %% 5 } # (25 30 35)

Now what?

Now we have to figure out what doc edits to propose...

Actually, before we do that, confirm that logical ops are supposed to not Whatever-curry...

And to start that ball rolling, I just trawled the results of a search for TimToady comments on #perl6 about "currying" (there were none on #perl6-dev), looking for ones pertinent to the case we have here.

First, one from 2017 that's arguably relevant to any doc edits:

the design docs actually try to avoid the word "currying" ... but it's hard to get people to use words differently than they do

Next, one from 2015 about && and || and such:

|| and && and such are really control flow operators, turned rather rapidly into 'if' and 'unless' ... those ops can be curried with .assuming, I assume

And finally a couple from 2010 that also seem potentially important (though perhaps one or more are no longer applicable?):

all operators autocurry a WhateverCode, whether or not they curry a Whatever

I think we can keep the current mechanism as a fallback for operators that still want to curry at run time

like image 157
raiph Avatar answered Oct 24 '22 11:10

raiph


> my $d = * + * + * 
> $d.arity
3
> my $e = * == 1 || * == 2 || * == 3 
> $e.arity
1

as the doc say:

Returns the minimum number of positional arguments that must be passed in order to call the code object.

so I think the all three star in * == 1 || * == 2 || * == 3 is the same thing.

> my $e = * == 1 && * == 2 && * > 3 
> $e(1)
False
> $e(2)
False
> $e(3)
False
> $e(4)
True
like image 2
chenyf Avatar answered Oct 24 '22 12:10

chenyf