There seems to be some inconsistent behavior when variables of the same letter-name but different sigils are used:
> my $a="foo";
foo
> my #a=1,2
[1 2]
> say $a
foo # this is what I have expected
> my $b = 1,2,3
(1 2 3)
> my #b = (0, $b.Slip)
[0 1] # I expect to get [0 1 2 3]; (0, |$b) not work either
> say $b
1 # I expect $b to be unchanged, (1,2,3), but it is now 1;
> say #a
[1 2]
> say #b
[0 1]
>
I am not sure why #a does not affect $a, whereas #b affects $b. Can someone please elucidate?
Thanks !!!
lisprog
In Rakudo Perl 6 there is actually no relationship at all between $b and #b.
$b didn't change. It simply didn't get assigned what you thought it had been assigned. Looking at the documentation on Operator Precedence, you'll see that = (assignment) has a tighter precedence than the comma ,.
Also, you are using the REPL, which automatically prints out the return value of each statement. That return value may or may not be the same as the value assigned to a variable.
my $b = 1,2,3 actually is the same as
(my $b = 1),2,3 because = has tighter precedence than ,, meaning that effectively all but the first value is ignored
> (my $b = 1),2,3
(1 2 3)
> $b
1
If you want to assign a list to $b, then put parentheses around the list:
> my $b = (1,2,3)
(1 2 3)
> $b
(1 2 3)
Related
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
>
Isn't order of execution generally from left to right in Raku?
my #a = my #b = [9 , 3];
say (#a[1] - #a[0]) == (#b[1] R- #b[0]); # False {as expected}
say (#a.pop() - #a.pop()) == (#b.pop() R- #b.pop()); # True {Huh?!?}
This is what I get in Rakudo(tm) v2020.12 and 2021.07.
The first 2 lines make sense, but the third I can not fathom.
It is.
But you should realize that the minus infix operator is just a subroutine under the hood, taking 2 parameters that are evaluated left to right. So when you're saying:
$a - $b
you are in fact calling the infix:<-> sub:
infix:<->($a,$b);
The R meta-operator basically creates a wrap around the infix:<-> sub that reverses the arguments:
my &infix:<R->($a,$b) = &infix:<->.wrap: -> $a, $b { nextwith $b, $a }
So, if you do a:
$a R- $b
you are in fact doing a:
infix:<R->($a,$b)
which is then basically a:
infix:<->($b,$a)
Note that in the call to infix:<R-> in your example, $a become 3, and $b becomes 9 because the order of the arguments is processed left to right. This then calls infix:<->(3,9), producing the -6 value that you would also get without the R.
It may be a little counter-intuitive, but I consider this behaviour as correct. Although the documentation could probably use some additional explanation on this behaviour.
Let me emulate what I assumed was happening in line 3 of my code prefaced with #a is the same as #b is 9, 3 (big number then little number)
(#a.pop() - #a.pop()) == (#b.pop() R- #b.pop())
(3 - 9) == (3 R- 9)
( -6 ) == ( 6 )
False
...That was my expectation. But what raku seems to be doing is
(#a.pop() - #a.pop()) == (#b.pop() R- #b.pop())
#R meta-op swaps 1st `#b.pop()` with 2nd `#b.pop()`
(#a.pop() - #a.pop()) == (#b.pop() - #b.pop())
(3 - 9) == (3 - 9)
( -6 ) == ( -6 )
True
The R in R- swaps functions first, then calls the for values. Since they are the same function, the R in R- has no practical effect.
Side Note: In fuctional programming a 'pure' function will return the same value every time you call it with the same parameters. But pop is not 'pure'. Every call can produce different results. It needs to be used with care.
The R meta op not only reverses the operator, it will also reverse the order in which the operands will be evaluated.
sub term:<a> { say 'a'; '3' }
sub term:<b> { say 'b'; '9' }
say a ~ b;
a
b
ab
Note that a happened first.
If we use R, then b happens first instead.
say a R~ b;
b
a
ba
The problem is that in your code all of the pop calls are getting their data from the same source.
my #data = < a b a b >;
sub term:<l> { my $v = #data.shift; say "l=$v"; return $v }
sub term:<r> { my $v = #data.shift; say "r=$v"; return $v }
say l ~ r;
l=a
r=b
ab
say l R~ r;
r=a
l=b
ab
A way to get around that is to use the reduce meta operator with a list
[-](#a.pop, #a.pop) == [R-](#a.pop, #a.pop)
Or in some other way make sure the pop operations happen in the order you expect.
You could also just use the values directly from the array without using pop.
[-]( #a[0,1] ) == [R-]( #a[2,3] )
Let me emulate what happens by writing the logic one way for #a then manually reversing the operands for #b instead of using R:
my #a = my #b = [9 , 3];
sub apop { #a.pop }
sub bpop { #b.pop }
say apop - apop; # -6
say bpop - bpop; # -6 (operands *manually* reversed)
This not only appeals to my sense of intuition about what's going on, I'm thus far confused why you were confused and why Liz has said "It may be a little counter-intuitive" and you've said it is plain unintuitive!
* > 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)
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
> 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
I've been trying to exercise my Perl 6 chops by looking at some golfing problems. One of them involved extracting the bits of an integer. I haven't been able to come up with a succinct way to write such an expression.
My "best" tries so far follow, using 2000 as the number. I don't care whether the most or least significant bit comes first.
A numeric expression:
map { $_ % 2 }, (2000, * div 2 ... * == 0)
A recursive anonymous subroutine:
{ $_ ?? ($_ % 2, |&?BLOCK($_ div 2)) !! () }(2000)
Converting to a string:
2000.fmt('%b') ~~ m:g/./
Of these, the first feels cleanest to me, but it would be really nice to be able to generate the bits in a single step, rather than mapping over an intermediate list.
Is there a cleaner, shorter, and/or more idiomatic way to get the bits, using a single expression? (That is, without writing a named function.)
The easiest way would be:
2000.base(2).comb
The .base method returns a string representation, and .comb splits it into characters - similar to your third method.
An imperative solution, least to most significant bit:
my $i = 2000; say (loop (; $i; $i +>= 1) { $i +& 1 })
The same thing rewritten using hyperoperators on a sequence:
say (2000, * +> 1 ...^ !*) >>+&>> 1
An alternative that is more useful when you need to change the base to anything above 36, is to use polymod with an infinite list of that base.
Most of the time you will have to reverse the order though.
say 2000.polymod(2 xx *);
# (0 0 0 0 1 0 1 1 1 1 1)
say 2000.polymod(2 xx *).reverse;
say [R,] 2000.polymod(2 xx*);
# (1 1 1 1 1 0 1 0 0 0 0)
When I compile the following Metapost file:
beginfig(1);
def f(expr n) =
if n=0: 0
else: 1
fi;
enddef;
show f(0)+1;
endfig;
end
I expect to get the output 1 (since f(0) is equal to 0, f(0)+1 should be 1!). However, Metapost complains about an Isolated expression.
When I put the expression in parentheses: show (f(0)+1), things get even stranger. The error message becomes : Missing ')' has been inserted. (The first quote should be a backquote, but I couldn't figure out how to escape it). Where on earth was there a mismatched parenthesis??
Thanks for your help!
The def command just expands a name into its definition, so you get literally:
show if 0=0: 0 else: 1;+1;
The semicolon in the middle is what's wrong, so let us remove it:
beginfig(1);
def f(expr n) =
if n=0: 0
else: 1
fi
enddef;
show f(0)+1;
endfig;
end
This produces the correct expansion:
show if 0=0: 0 else: 1+1;
And outputs 1 as expected.
On a side note, I'd recommend using begingroup...endgroup for heavier macro definitions, and at least parentheses for lighter ones: for example,
def f = 1 + 2 enddef;
show f * 2;
gives 1 + 2 * 2, which is not the same as what is probably expected:
def f = (1 + 2) enddef;
show f * 2;
which gives (1 + 2) * 2.