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?!?}
Run Code Online (Sandbox Code Playgroud)
这是我在 Rakudo(tm) v2020.12 和 2021.07 中得到的。前两行有道理,但第三行我无法理解。
这是。
但是您应该意识到减号中缀运算符只是底层的一个子程序,采用从左到右计算的 2 个参数。所以当你说:
$a - $b
Run Code Online (Sandbox Code Playgroud)
你实际上是在调用infix:<->sub:
infix:<->($a,$b);
Run Code Online (Sandbox Code Playgroud)
该R荟萃运营商基本上创建了一个包裹围绕infix:<->该反转的参数子:
my &infix:<R->($a,$b) = &infix:<->.wrap: -> $a, $b { nextwith $b, $a }
Run Code Online (Sandbox Code Playgroud)
因此,如果您执行以下操作:
$a R- $b
Run Code Online (Sandbox Code Playgroud)
你实际上是在做:
infix:<R->($a,$b)
Run Code Online (Sandbox Code Playgroud)
那么基本上是一个:
infix:<->($b,$a)
Run Code Online (Sandbox Code Playgroud)
需要注意的是在调用infix:<R->你的榜样,$a成为3,并$b成为9由于参数的顺序进行处理从左到右。然后调用infix:<->(3,9),产生-6没有R.
这可能有点违反直觉,但我认为这种行为是正确的。尽管文档可能会对这种行为使用一些额外的解释。
让我模拟一下我假设在我的代码的第 3 行中发生的事情,以@a 开头与@b 相同,即为 9, 3(大数然后小数)
(@a.pop() - @a.pop()) == (@b.pop() R- @b.pop())
(3 - 9) == (3 R- 9)
( -6 ) == ( 6 )
False
Run Code Online (Sandbox Code Playgroud)
......这是我的期望。但是 raku 似乎在做的是
(@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
Run Code Online (Sandbox Code Playgroud)
R-中的R首先交换函数,然后调用for值。由于它们是同一个函数,R-中的R没有实际作用。
旁注:在函数式编程中,“纯”函数每次使用相同的参数调用时都会返回相同的值。但流行并不“纯粹”。每次调用都会产生不同的结果。它需要小心使用。
所述R元运算不仅反转操作者,它也将反转,其中操作数将被评估的顺序。
sub term:<a> { say 'a'; '3' }
sub term:<b> { say 'b'; '9' }
say a ~ b;
Run Code Online (Sandbox Code Playgroud)
a
b
ab
Run Code Online (Sandbox Code Playgroud)
请注意,这a首先发生。
如果我们使用R,则b先发生。
say a R~ b;
Run Code Online (Sandbox Code Playgroud)
b
a
ba
Run Code Online (Sandbox Code Playgroud)
问题是在您的代码中,所有pop调用都从同一来源获取数据。
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;
Run Code Online (Sandbox Code Playgroud)
l=a
r=b
ab
Run Code Online (Sandbox Code Playgroud)
say l R~ r;
Run Code Online (Sandbox Code Playgroud)
r=a
l=b
ab
Run Code Online (Sandbox Code Playgroud)
解决这个问题的一种方法是使用带有列表的 reduce 元运算符
[-](@a.pop, @a.pop) == [R-](@a.pop, @a.pop)
Run Code Online (Sandbox Code Playgroud)
或者以其他方式确保pop操作按您期望的顺序进行。
您也可以直接使用数组中的值而不使用pop.
[-]( @a[0,1] ) == [R-]( @a[2,3] )
Run Code Online (Sandbox Code Playgroud)