这是我所期望的。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);
最后一个版本永远不会返回。有没有办法编写一个没有返回值的匿名递归函数?
根据留档:
不是Routine类型(它是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
}
}
还有三种选择:
您可以使用不带名称的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的答案,了解为什么这(故意)不适用于非常规块。
该设计预见到您的问题:
my $fib = -> Int $x --> Int {
leave 0 if $x == 0;
leave 1 if $x == 1;
leave $fib($x - 1) + $fib($x - 2);
}
编译。希望你能猜到它所做的——或者更确切地说应该做的——正是你想做的。
不幸的是,如果您遵循上述内容:
say $fib(13);
您会收到一个运行时错误“尚未实现休假”。
我的猜测是,这将在未来几年的某个时候实现,然后“尝试在任何例程之外返回”错误消息将提到离开
。但是实现它的优先级非常低,因为像上面写sub
很容易,或者像@HåkonHægland那样写代码,或者像下面这样使用case/switch语句构造,现在已经足够好了。
您可以将参数指定为$_
而不是$x
,然后您就可以使用引用主题的构造:
my $fib = -> Int $_ --> Int {
when 0 { 0 }
when 1 { 1 }
$fib($_ - 1) + $fib($_ - 2)
}
say $fib(13); # 233
参见时
。
块不需要声明返回类型。不过,您仍然可以返回任何您想要的东西。问题不在于使用返回,而在于Int的声明。
use v6;
my $fib = -> Int $x {
if $x == 0 {
0;
} elsif $x == 1 {
1;
} else {
$fib($x - 1) + $fib($x - 2);
}
}
say $fib(13) ;
问题是返回值需要是最后执行的。按照你的方式,如果它找到0或1,它会继续运行,到达最后一条语句,然后它会重新开始。或者,你可以使用给定的而不是级联的ifs。只要它返回的是最后发出的,就没问题。