223

是否有可能有一个递归和匿名的 PHP 函数?这是我让它工作的尝试,但它没有传入函数名。

$factorial = function( $n ) use ( $factorial ) {
    if( $n <= 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );

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

4

6 回答 6

410

为了让它工作,你需要传递 $factorial 作为参考

$factorial = function( $n ) use ( &$factorial ) {
    if( $n == 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
于 2010-03-19T20:03:09.740 回答
25

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

不动点是由函数改变的值:函数f的不动点是满足 x = f(x)的任意x 。定点组合器y是一个函数,它为任何函数 f 返回一个不动点。因为 y(f) 是 f 的一个不动点,所以我们有 y(f) = f(y(f))。

本质上,Y 组合器创建了一个新函数,该函数接受原始函数的所有参数,以及一个附加参数,即递归函数。使用柯里化符号可以更清楚地了解其工作原理。不要将参数写在括号 ( f(x,y,...)) 中,而是将它们写在函数之后:f x y ...。Y 组合器定义为Y f = f (Y f); 或者,使用递归函数的单个参数,Y f x = f (Y f) x.

由于 PHP 不会自动对函数进行curry,因此工作起来有点麻烦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 );

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

于 2010-05-05T14:19:03.937 回答
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)
于 2017-04-09T08:21:43.797 回答
0

在较新版本的 PHP 中,您可以这样做:

$x = function($depth = 0) {
    if($depth++)
        return;

    $this($depth);
    echo "hi\n";
};
$x = $x->bindTo($x);
$x();

这可能会导致奇怪的行为。

于 2017-09-20T13:36:29.947 回答
0

您可以在 PHP 7.1+ 中使用 Y Combinator,如下所示:

function Y
($le)
{return
    (function ($f) 
     {return
        $f($f);
     })(function ($f) use ($le) 
        {return
            $le(function ($x) use ($f) 
                {return
                    $f($f)($x);
                });
        });
}

$le =
function ($factorial)
{return
    function
    ($n) use ($factorial)
    {return
        $n < 2 ? $n
        : $n * $factorial($n - 1);
    };
};

$factorial = Y($le);

echo $factorial(1) . PHP_EOL; // 1
echo $factorial(2) . PHP_EOL; // 2
echo $factorial(5) . PHP_EOL; // 120

玩它:https ://3v4l.org/7AUn2

源代码来自:https ://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php

于 2019-07-29T01:53:46.513 回答
0

使用匿名类(PHP 7+),不定义变量:

echo (new class {
    function __invoke($n) {
        return $n < 2 ? 1 : $n * $this($n - 1);
    }
})(5);
于 2019-11-12T00:22:04.913 回答