在Perl上有一个计算factorial N的递归实现。
sub fact {
my ($n) = shift;
return $n if $n <= 2;
return $n * fact($n - 1);
}
有人可以解释一下Perl在函数给出结果之前保存中间结果的地方吗?
UPD 以及如何使用调试器或使用其他内容来查看它们?
从答案我解释说这个值保存在堆栈中,但我怎么能从堆栈中看到这些值?
答案 0 :(得分:2)
$n
返回的标量存储在堆栈中。
这就是在调用fact
之前堆栈的样子:
$n
在递归级别0中返回的标量$n
在递归级别1中返回的标量$n
在递归级别2中返回的标量$n-1
在递归级别2中返回的标量\&fact
在递归级别2中返回的标量这就是在调用fact
之后堆栈的样子:
$n
在递归级别0中返回的标量$n
在递归级别1中返回的标量$n
在递归级别2中返回的标量fact($n - 1)
在递归级别2中返回的标量此时,乘法运算符将乘以堆栈上的最后两个值,并将结果放在堆栈上。
$n
在递归级别0中返回的标量$n
在递归级别1中返回的标量$n * fact($n - 1)
在递归级别2中返回的标量然后子回归,
$n
在递归级别0中返回的标量$n
在递归级别1中返回的标量fact($n - 1)
在递归级别1中返回的标量等等。
答案 1 :(得分:2)
使用递归,每次调用中传递的任何参数都会在调用帧/堆栈上进行。使用Carp&amp;咯咯,你可以看到调用帧。当堆栈在到达基本情况时展开($ v == 1)时计算中间结果。它只能在CPU寄存器中吗?运算符(*)将此中间结果与堆栈上的$ v相乘。结帐this article。
#!/usr/bin/env perl
use strict;
use IO::Handle;
use Carp qw(cluck);
STDOUT->autoflush(1);
STDERR->autoflush(1);
sub factorial {
my $v = shift;
dummy_func();
return 1 if $v == 1;
print "Variable v value: $v and it's address:", \$v, "\ncurrent sub factorial addr:", \&factorial, "\n","-"x40;
return $v * factorial($v - 1);
}
sub dummy_func {
cluck;
}
factorial(5);
同样在调试模式下运行会有所帮助。
perl -d factorial.pl
答案 2 :(得分:1)
任何调用的中间结果都保存在堆栈中,就像函数中的局部变量一样。
return $n * fact($n - 1);
等同于:
my $temp = fact($n - 1);
return $n * $temp;
更新:我发现您在退货之前也对产品的位置感兴趣。这也是一个临时的堆栈,所以它相当于:
my $temp1 = fact($n - 1);
my $temp2 = $n * $temp1;
return $temp2;
答案 3 :(得分:1)
由于$n
被声明为my $n
,因此它是一个词法范围的变量,存储在堆栈中,而不是存储在系统表中。有关详细信息,请参阅Perl Variables via my()。