Raku lambdas 的意外行为应该是相等的(我猜)

Unexpected behaviours with Raku lambdas that are supposed to be equal (I guess)

我正在学习 Raku 作为一个充满激情的项目,我想实现一个 简单的 fizzbuzz,为什么 join 只有在我用尖块编写 lambda 时才保留嗡嗡声?

my $iif =-> $x,$y,$z {if $x {$y} else {$z}}
my $modToString =-> $x,$y,$z {$iif($x%%$y,$z,'')}
my $FB =-> $x {join($modToString($x,3,'fizz'),$modToString($x,5,'buzz'))}
my $logic =-> $x {$iif($FB($x),$FB($x),$x)}
say map(-> $x {$logic($x)}, 1..100)

$modToString(1,3,'fizz')
> 
$modToString(3,3,'fizz')
> fizz
$modToString(3,5,'buzz')
> 
$modToString(5,5,'buzz')
> buzz

如果我将尖块变量转换为占位符变量,Rakudo 会抛出错误:

my $iif = {if $^x {$^y} else {$^z}};
my $modToString = {$iif($^x%%$^y,$^z,'')};
my $FB = {join($modToString($^x,3,'fizz'),$modToString($^x,5,'buzz'))}
my $logic = {$iif($FB($^x),$FB($^x),$^x)}
say map(-> $x {$logic($x)}, 1..100)

Too many positionals passed; expected 1 argument but got 3
  in block  at <unknown file> line 1
  in block  at <unknown file> line 1
  in block  at <unknown file> line 1
  in block  at <unknown file> line 1
  in block <unit> at <unknown file> line 1

如果我将连接参数放在方括号中,它只会输出数字:

my $iif =-> $x,$y,$z {if $x {$y} else {$z}}
my $modToString =-> $x,$y,$z {$iif($x%%$y,$z,'')}
my $FB =-> $x {join(<$modToString($x,3,'fizz'),$modToString($x,5,'buzz')>)}
my $logic =-> $x {$iif($FB($x),$FB($x),$x)}
say map(-> $x {$logic($x)}, 1..100)

为什么?

因为乐库中很多的东西都是方块,即使是看起来不像的东西。特别是,这包括控制流程的“参数”,如 if.

if 1 { 2 } else { 3 }

我们实际上在这里写了两个街区。一个是返回 2 的常量函数,另一个是返回 3 的常量函数。现在,通常,这对我们来说是透明的,Raku 引擎足够聪明,可以将它们编译掉。但他们还在那里。事实上,我们可以使它们显式化。以下行为与上述 if 语句相同。

if 1 -> { 2 } else -> { 3 }

然而,在你的情况下,它最终很重要。匿名参数(带有 ^ twigil 的参数)绑定到最里面的块。所以你写了

{if $^x {$^y} else {$^z}}

并且您希望它等同于

-> $x, $y, $z {if $x {$y} else {$z}}

但你实际写的是

-> $x {if $x -> $y {$y} else -> $z {$z}};

因此,正如错误消息所述,您确实编写了一个只有一个参数的函数并向其传递了三个参数。

作为一个广泛的规则,您通常可以假设 任何时候 您看到一个 {,它要么以哈希文字开始,要么以块开始。后者总是引入一个范围,其中可以存在局部变量和参数。

在您的特定情况下,您可以使用三元运算符 ??!!(这与大多数其他语言(如 C++ 或 Java 中的 ?: 相同)

{$^x ?? $^y !! $^z}

这个运算符没有 short-circuit 也没有引入块,所以它可以正常工作。

正在将 OP 的解决方案从问题迁移到答案。

After I understood the problem and they also pointed out that I wrote a pointless ternary operator!

I also typed join instead of the tilde! I'm happy to say that my fizzbuzz now works:

my $modToString =-> $x,$y,$z {$x%%$y??$z!!''}
my $FB =-> $x {$modToString($x,3,'fizz')~$modToString($x,5,'buzz')}
my $logic =-> $x {$FB($x)??$FB($x)!!$x}
say map(-> $x {$logic($x)}, 1..100)