如何从perl6中的匿名递归子返回?

jmc*_*ney 9 perl6 raku

这就是我所期待的.fib(13)返回233.

sub fib(Int $a --> Int) {
    return 0 if $a == 0;
    return 1 if $a == 1;

    return fib($a -1) + fib($a -2);
}

my $square = -> $x { $x * 2 };   # this works with no return value
my @list = <1 2 3 4 5 6 7 8 9>.map( $square );
# returns [2 4 6 8 10 12 14 16 18]
Run Code Online (Sandbox Code Playgroud)

我尝试使用匿名子实现fib()

my $fib = -> Int $x --> Int {
    return 0 if $x == 0;
    return 1 if $x == 1;
    return $fib($x - 1) + $fib($x - 2); 
}

$fib(13) 
Run Code Online (Sandbox Code Playgroud)

使用显式返回运行时出现以下错误.

尝试在test.p6第39行的块中返回任何例程

所以我摆脱了返回值.

my $fib = -> Int $x --> Int {
    0 if $x == 0;
    1 if $x == 1;
    $fib($x - 1) + $fib($x - 2); 
}

say $fib(13);
Run Code Online (Sandbox Code Playgroud)

最后一个版本永远不会返回 有没有办法编写一个没有返回值的匿名递归函数?

Håk*_*and 9

根据文件:

不是Routine类型的块(它是Block的子类)对于返回是透明的.

sub f() {
say <a b c>.map: { return 42 };
               #   ^^^^^^   exits &f, not just the block  }
Run Code Online (Sandbox Code Playgroud)

最后一个语句是块的隐式返回值

所以你可以尝试:

my $fib = -> Int $x --> Int {
    if ( $x == 0 ) {
        0;  # <-- Implicit return value
    }
    elsif ( $x == 1 ) {
        1;  # <-- Implicit return value
    }
    else {
        $fib($x - 1) + $fib($x - 2);  # <-- Implicit return value
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 隐式形式很漂亮,虽然另一个选项也许值得一提的是写`sub(Int $ x - > Int){...}` - 也就是说,一个真正的匿名子 - 其余的工作原来是它最初编写的. (2认同)

rai*_*iph 7

还有三个选择:

sub

您可以通过使用没有名称来编写匿名例程sub:

my $fib = sub (Int $x --> Int) {
  return 0 if $x == 0;
  return 1 if $x == 1;
  return $fib($x - 1) + $fib($x - 2); 
}

say $fib(13); # 233
Run Code Online (Sandbox Code Playgroud)

请参阅@HåkonHægland的答案,了解为什么这(故意)不适用于非常规块.

leave

设计预计了你的问题:

my $fib = -> Int $x --> Int {
  leave 0 if $x == 0;
  leave 1 if $x == 1;
  leave $fib($x - 1) + $fib($x - 2); 
}
Run Code Online (Sandbox Code Playgroud)

编译.希望你能猜到它的作用 - 或者更确切地说应该做的 - 正是你想要做的.

不幸的是,如果你按照上面的说法:

say $fib(13);
Run Code Online (Sandbox Code Playgroud)

你得到一个运行时错误"还没有实现".

我的猜测是,这将在未来几年内实施一段时间,然后提及"尝试返回任何常规"错误消息leave.但是实现它的优先级非常低,因为它很容易sub按上面的方式编写,或者像@HåkonHægland那样编写代码,或者使用case/switch语句结构,如下所示,现在已经足够好了.

案例/开关(when/ default)

您可以指定参数$_而不是,$x然后您将全部设置为使用引用该主题的构造:

my $fib = -> Int $_ --> Int {
  when 0 { 0 }
  when 1 { 1 }
  $fib($_ - 1) + $fib($_ - 2)
}

say $fib(13); # 233
Run Code Online (Sandbox Code Playgroud)

when.