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

发布于 2025-01-17 06:24:01 字数 1455 浏览 1 评论 0原文

我正在学习 Raku 作为一个热情项目,我想实现一个简单 fizzbuzz,为什么如果我用尖头块编写 lambda 表达式,join 只会保留嗡嗡声?

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)

为什么?

I'm learning Raku as a passion project and I wanted to implement a simple fizzbuzz, why is join only retaining buzz if I write lambdas with pointy blocks?

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

If I transform the pointy blocks variables into placeholder variables, Rakudo throws an error:

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

If I put the brackets around the join arguments it just outputs the numbers:

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)

Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

简美 2025-01-24 06:24:01

因为 Raku 中的很多东西都是块,甚至是看起来不像的东西。特别是,这包括控制流程的“参数”,如 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}

此运算符不不会短路,也不会引入阻塞,因此它可以正常工作。

Because lots of things in Raku are blocks, even things that don't look like it. In particular, this includes the "argument" to control flow like if.

if 1 { 2 } else { 3 }

We've actually written two blocks here. One is a constant function returning 2 and the other is a constant function returning 3. Now, usually, this is transparent to us and the Raku engine is smart enough to compile those away. But they're still there. In fact, we can make them explicit. The following behaves identically to the above if statement.

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

In your case, however, it ends up mattering. Anonymous arguments (the ones with the ^ twigil) bind to the innermost block. So you've written

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

and you intended that it be equivalent to

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

but what you actually wrote was

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

So you've really written a function of one argument and passed it three arguments, as the error message states.

As a broad rule, you can generally assume that anytime you see a {, it either begins a hash literal or a block. And the latter always introduces a scope in which local variables and arguments can exist.

In your particular case, you can use the ternary ??!! operator (this is the same thing as ?: in most other languages like C++ or Java)

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

This operator doesn't short-circuit and doesn't introduce blocks, so it'll work fine.

忆离笙 2025-01-24 06:24:01

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

Silvio Mayolo 的回答 我理解了这个问题,他们还指出我写了一个毫无意义的三元组运算符!

我还输入了 join 而不是波浪号!我很高兴地说我的 fizzbuzz 现在可以工作了:

我的 $modToString =-> $x,$y,$z {$x%%$y??$z!!''}
我的$FB =-> $x {$modToString($x,3,'嘶嘶')~$modToString($x,5,'嗡嗡声')​​}
我的 $logic =-> $x {$FB($x)??$FB($x)!!$x}
说地图(-> $x {$logic($x)}, 1..100)

Migrating OP's solution from the question to an answer.

After Silvio Mayolo's answer 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文