阶乘递归达到零时出错

时间:2017-02-23 21:00:15

标签: perl function recursion error-handling parameter-passing

为什么以下递归因子在Perl中失败,即使它在C ++和Java中有效?

爪哇:

public static long factorial(int n) {
  if (n == 0) {
    return 1;
  } else {
    return factorial(n-1) * n;
  }
}

C ++:

long factorial(int n) {
  if (n == 0)
    return 1;
  else
    return n * factorial(n-1);
}

但是这个在Perl(use Carp;)中失败了:

sub factorial {
    my $n = shift || croak "null value for argument";
    return 1 if $n == 0;  # base case
    return  $n * factorial($n-1);
}

错误消息(第10行是main()中调用函数的地方,第16行是第二个return语句):

 null value for argument at ./fact1.pl line 14.
        main::factorial(0) called at ./fact1.pl line 16
        main::factorial(1) called at ./fact1.pl line 10

(以下编辑归功于Matt Jacob在原版中指出我的遗漏。)

原始版本,没有鲤鱼,但有|| return,错误消息是:

Use of uninitialized value in multiplication (*) at ./fact1.pl line 16.

这是在没有命令行参数时尝试使脚本保持静默的结果。 (没有关于uninitialized value的投诉。)

对基本案例的一个小修改使它在Perl中也可以工作:

sub factorial {
    my $n = shift || croak "null value for argument";
    return 1 if $n == 1;  # base case
    return $n * factorial($n-1);
}

(当然,代价是取消处理0(零)输入。)

经验教训

  1. 问题发生在我想到的不同位置
    • Perl代码在尝试比C ++或Java代码片段做的更多的部分中有错误(一种非常粗略的方法)
    • 不同的错误消息应该给我一个提示
  2. 以下内容可以帮我定位问题:
    • shift;
    • 之后删除所有内容
    • 请记住0(零)表示false
  3. 自版本5.10 以来,
  4. Logical Defined-Or存在于Perl中
  5. 至于正确的错误处理,this page提供了一个很好的概述。

1 个答案:

答案 0 :(得分:6)

对于被认为是真实的东西,Perl有一些相当不正统的规则。

特别是,在布尔表达式中使用时,数字0被认为是假的。所以当你这样说时

my $n = shift || croak "null value for argument";

如果shift将0作为参数,则会将其视为false,这意味着||运算符需要计算其第二个操作数。

幸运的是,Perl的编写者预见到了这种用例,因此他们定义了一个替代或运算符。 ||检查第一个值是否真实,//检查是否定义了第一个值。

my $n = shift // croak "null value for argument";

这将按照您的意图执行,除非$n可能是文字值undef。在这种情况下,你需要一些更复杂的内省来检查参数是否存在,但是为了这个阶乘函数的目的,这应该足够了。