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

问题描述 投票:9回答:3

这符合我的期望。 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]

我尝试使用匿名子实现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) 

运行带有显式返回的错误时出现以下错误。

试图返回任何例程之外在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);

此最新版本永不返回。有没有办法编写没有返回值的匿名递归函数?

perl6 raku
3个回答
9
投票

根据the documentation

不是常规类型的块(它是Block的子类)是透明返回。

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

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

所以您可以尝试:

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
    }
}

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

请参阅@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); 
}

编译。希望您能猜到它所做的-确切地说是is supposed to do-正是您想要做的。

不幸的是,如果您遵循上述要求:

say $fib(13);

您收到运行时错误“尚未执行”。

我的猜测是,这将在未来几年内实现,并且“尝试返回任何例程之外的错误”错误消息将提到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

请参见when


4
投票

when。不过,您仍然可以返回任何想要的东西。问题不在于使用return,而是在Int的声明中。

© www.soinside.com 2019 - 2024. All rights reserved.