Perl 递归匿名函数来计算级数和

Perl 递归匿名函数来计算级数和,perl,recursion,anonymous-function,Perl,Recursion,Anonymous Function,我试着写一个函数来计算, 我所能想到的就是这个,它不起作用 $fact = sub { $n = shift; if($n==0 || $n ==1){ return 1; }else{ return $n*&$fact($n-1); } } sub fun{ ($x,$n)= @_; if($n==0){ return 1; }elsif($n == 1){ re

我试着写一个函数来计算,

我所能想到的就是这个,它不起作用

$fact = sub {
    $n = shift;
    if($n==0 || $n ==1){
        return 1;
    }else{
        return $n*&$fact($n-1);
    }
}

sub fun{
    ($x,$n)= @_;
    if($n==0){
        return 1;
    }elsif($n == 1){
        return $x;
    }else{
        return ($x)/&$fact($n)+fun($x,$n-1);
    }
}



print (fun(3,5));

首先,始终使用

use strict;
use warnings qw( all );
它会抓住你的一个错误


其次,你把你的潜艇命名错误,你错过了一个
my
,你发明了一个特例(因为
($x**1)/1!==$x
)[1]。忽略目前匿名的需要,
f
只是:

sub f {
   my ($x, $n) = @_;
   return 1 if $n == 0;
   return ($x**$n) / fact($x) + f($x, $n-1);
}
sub fact {
   my ($n) = @_;
   my $acc = 1;
   $acc *= $_ for 1..$n;
   return $acc;
}
类似地,
事实
也只是:

sub f {
   my ($x, $n) = @_;
   return 1 if $n == 0;
   return ($x**$n) / fact($x) + f($x, $n-1);
}
sub fact {
   my ($n) = @_;
   my $acc = 1;
   $acc *= $_ for 1..$n;
   return $acc;
}

关于这个问题,使递归函数匿名只是将递归调用替换为
\uuuu SUB\uuu->(…)
[2]的问题,因此以下是匿名版本:

use feature qw( current_sub );

my $f = sub {
   my ($x, $n) = @_;
   return 1 if $n == 0;
   return ($x**$n) / fact($x) + __SUB__->($x, $n-1);
};
如果你也希望
fact
匿名

use feature qw( current_sub );

my $f = sub {
   my ($x, $n) = @_;
   return 1 if $n == 0;

   my $fact = sub {
      my ($n) = @_;
      my $acc = 1;
      $acc *= $_ for 1..$n;
      return $acc;
   };

   return ($x**$n) / $fact->($x) + __SUB__->($x, $n-1);
};

也就是说,对于这个函数来说,使用递归是一种巨大的浪费。下面是一个高效的实现:

my $f = sub {
   my ($x, $n) = @_;

   my $acc             = 1;
   my $numerator_acc   = 1;
   my $denominator_acc = 1;
   for (1..$n) {
      $numerator_acc   *= $x;
      $denominator_acc *= $_;
      $acc += ( $numerator_acc / $denominator_acc );
   }

   return $acc;
};

  • 从技术上讲,你从
    ($x**0)/0!==1
    ,但无论发生什么情况,
    $n==0
    都必须在一定程度上进行特殊处理

  • Perl 5.16中引入了
    \uuuuuuuu SUB\uuuuuuuuu
    。如果您想避免内存泄漏,那么在此之前就更复杂了


  • 首先,始终使用

    use strict;
    use warnings qw( all );
    
    它会抓住你的一个错误


    其次,你把你的潜艇命名错误,你错过了一个
    my
    ,你发明了一个特例(因为
    ($x**1)/1!==$x
    )[1]。忽略目前匿名的需要,
    f
    只是:

    sub f {
       my ($x, $n) = @_;
       return 1 if $n == 0;
       return ($x**$n) / fact($x) + f($x, $n-1);
    }
    
    sub fact {
       my ($n) = @_;
       my $acc = 1;
       $acc *= $_ for 1..$n;
       return $acc;
    }
    
    类似地,
    事实
    也只是:

    sub f {
       my ($x, $n) = @_;
       return 1 if $n == 0;
       return ($x**$n) / fact($x) + f($x, $n-1);
    }
    
    sub fact {
       my ($n) = @_;
       my $acc = 1;
       $acc *= $_ for 1..$n;
       return $acc;
    }
    

    关于这个问题,使递归函数匿名只是将递归调用替换为
    \uuuu SUB\uuu->(…)
    [2]的问题,因此以下是匿名版本:

    use feature qw( current_sub );
    
    my $f = sub {
       my ($x, $n) = @_;
       return 1 if $n == 0;
       return ($x**$n) / fact($x) + __SUB__->($x, $n-1);
    };
    
    如果你也希望
    fact
    匿名

    use feature qw( current_sub );
    
    my $f = sub {
       my ($x, $n) = @_;
       return 1 if $n == 0;
    
       my $fact = sub {
          my ($n) = @_;
          my $acc = 1;
          $acc *= $_ for 1..$n;
          return $acc;
       };
    
       return ($x**$n) / $fact->($x) + __SUB__->($x, $n-1);
    };
    

    也就是说,对于这个函数来说,使用递归是一种巨大的浪费。下面是一个高效的实现:

    my $f = sub {
       my ($x, $n) = @_;
    
       my $acc             = 1;
       my $numerator_acc   = 1;
       my $denominator_acc = 1;
       for (1..$n) {
          $numerator_acc   *= $x;
          $denominator_acc *= $_;
          $acc += ( $numerator_acc / $denominator_acc );
       }
    
       return $acc;
    };
    

  • 从技术上讲,你从
    ($x**0)/0!==1
    ,但无论发生什么情况,
    $n==0
    都必须在一定程度上进行特殊处理

  • Perl 5.16中引入了
    \uuuuuuuu SUB\uuuuuuuuu
    。如果您想避免内存泄漏,那么在此之前就更复杂了


  • 你把你的两个功能搞混了。sub
    fact
    只接受一个数字n,并返回n!。您需要定义一个单独的函数,该函数使用
    fact
    计算原始和,并调用它。此外,如果您真的要生成一个匿名和递归的函数,则需要使用某种零点组合器。@Mark Reed,在执行递归sub时,临时为其创建一个名称要容易得多:
    sub{local*\u r=sub{…\u r(…)…};\u r(@)}
    。这两个函数混淆了。sub
    fact
    只接受一个数字n,并返回n!。您需要定义一个单独的函数,该函数使用
    fact
    计算原始和,并调用它。此外,如果您真的要生成一个匿名和递归的函数,则需要使用某种零点组合器。@Mark Reed,在执行递归sub时,临时为其创建一个名称要容易得多:
    sub{local*\ur=sub{…\ur(…)…};\ur(@)}
    。哇!令人惊叹的你真是个天才!SUB->($x$n-1),你能解释一下这个部分吗。或者添加到教程的链接来了解这一点?返回对当前执行的子例程的引用。
    ->()
    是通过引用调用子例程的方式;例如,您需要调用
    $f->(3,5)
    将ikegami的实现用于示例输入。哇!令人惊叹的你真是个天才!SUB->($x$n-1),你能解释一下这个部分吗。或者添加到教程的链接来了解这一点?返回对当前执行的子例程的引用。
    ->()
    是通过引用调用子例程的方式;例如,您需要调用
    $f->(3,5)
    以将ikegami的实现用于示例输入。