匿名递归PHP函数

Ken*_*ins 190 php recursion lambda closures anonymous-function

是否可以使用递归和匿名的PHP函数?这是我试图让它工作,但它没有传递函数名称.

$factorial = function( $n ) use ( $factorial ) {
    if( $n <= 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
Run Code Online (Sandbox Code Playgroud)

我也知道这是实现阶乘的一种不好的方法,它只是一个例子.

Der*_*k H 342

为了使其工作,您需要传递$ factorial作为参考

$factorial = function( $n ) use ( &$factorial ) {
    if( $n == 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
Run Code Online (Sandbox Code Playgroud)

  • @cellbeauty在$ factorial被传递的时候,它仍然是null(未定义),这就是你必须通过引用传递它的原因.请注意,如果在调用函数之前修改$ factorial,则结果将随引用传递而更改. (24认同)
  • @ellabeauty:不,你完全误解了它.没有"&"的一切都是有价值的."&"的所有内容都是参考."对象"不是PHP5中的值,无法分配或传递.您正在处理其值为对象引用的变量.像所有变量一样,它可以通过值或引用来捕获,具体取决于是否存在"&". (9认同)
  • 心灵吹!非常感谢!到现在为止我怎么也不知道呢?我对递归匿名函数的应用程序量很大.现在我终于可以遍历布局中的嵌套结构,而无需显式定义方法并将所有布局数据保留在我的类之外. (3认同)

Ken*_*ins 24

我知道这可能不是一个简单的方法,但我从函数式语言中学到了一种称为"修复"的技术.fix来自Haskell 的函数更普遍地被称为Y组合器,其是最着名的定点组合器之一.

固定点是由函数不变的值:函数f的固定点是任何x,使得x = f(x).定点组合器y是返回任何函数f的固定点的函数.由于y(f)是f的固定点,因此我们得到y(f)= f(y(f)).

本质上,Y组合器创建一个新函数,它接受原始的所有参数,以及一个附加参数,即递归函数.使用curry表示法,这是如何工作的更明显.不是在括号(f(x,y,...))中写入参数,而是在函数之后写入:f x y ....Y组合子定义为Y f = f (Y f); 或者,使用递归函数的单个参数,Y f x = f (Y f) x.

由于PHP不会自动咖喱的功能,这是一个黑客位做出的fix工作,但我认为这是有趣的.

function fix( $func )
{
    return function() use ( $func )
    {
        $args = func_get_args();
        array_unshift( $args, fix($func) );
        return call_user_func_array( $func, $args );
    };
}

$factorial = function( $func, $n ) {
    if ( $n == 1 ) return 1;
    return $func( $n - 1 ) * $n;
};
$factorial = fix( $factorial );

print $factorial( 5 );
Run Code Online (Sandbox Code Playgroud)

请注意,这与其他人发布的简单闭包解决方案几乎相同,但该功能fix为您创建了闭包.固定点组合器比使用闭合器稍微复杂一些,但更通用,还有其他用途.虽然闭包方法更适合PHP(这不是一种非常功能的语言),但原始问题更多的是练习而不是生产,因此Y组合器是一种可行的方法.

  • @Xeoncross与设置陆地速度记录的PHP的其余部分相反?:P (11认同)
  • 值得注意的是,`call_user_func_array()`在圣诞节时很慢. (10认同)

mpy*_*pyw 5

尽管它不是用于实际用途,但C级扩展mpyw-junks / phpext-callee提供了匿名递归而不分配变量

<?php

var_dump((function ($n) {
    return $n < 2 ? 1 : $n * callee()($n - 1);
})(5));

// 5! = 5 * 4 * 3 * 2 * 1 = int(120)
Run Code Online (Sandbox Code Playgroud)