是否可以使用递归和匿名的PHP函数?这是我试图让它工作,但它没有传递函数名称 .
$factorial = function( $n ) use ( $factorial ) { if( $n <= 1 ) return 1; return $factorial( $n - 1 ) * $n; }; print $factorial( 5 );
我也知道这是实现阶乘的一种不好的方法,它只是一个例子 .
为了使其工作,您需要传递$ factorial作为参考
$factorial = function( $n ) use ( &$factorial ) { if( $n == 1 ) return 1; return $factorial( $n - 1 ) * $n; }; print $factorial( 5 );
我知道这可能不是一个简单的方法,但我从函数式语言中学到了一种名为"fix"的技术 . 来自Haskell的 fix 函数更常被称为Y combinator,它是最着名的fixed point combinators之一 .
fix
固定点是由函数不变的值:函数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 .
f(x,y,...)
f x 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组合器是一种可行的方法 .
虽然它不适用于实际用途,但C级扩展mpyw-junks/phpext-callee提供了匿名递归 without assigning variables .
<?php var_dump((function ($n) { return $n < 2 ? 1 : $n * callee()($n - 1); })(5)); // 5! = 5 * 4 * 3 * 2 * 1 = int(120)
在较新版本的PHP中,您可以这样做:
$x = function($depth = 0) { if($depth++) return; $this($depth); echo "hi\n"; }; $x = $x->bindTo($x); $x();
这可能会导致奇怪的行为 .
4 回答
为了使其工作,您需要传递$ factorial作为参考
我知道这可能不是一个简单的方法,但我从函数式语言中学到了一种名为"fix"的技术 . 来自Haskell的
fix
函数更常被称为Y combinator,它是最着名的fixed point combinators之一 .固定点是由函数不变的值:函数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不会自动curry函数,所以使
fix
工作有点麻烦,但我认为它很有趣 .请注意,这几乎与其他人发布的简单闭包解决方案相同,但函数
fix
为您创建了闭包 . 固定点组合器比使用闭合器稍微复杂一些,但更通用,并具有其他用途 . 虽然闭包方法更适合PHP(它不是一种非常功能的语言),但最初的问题更多的是练习而不是 生产环境 ,因此Y组合器是一种可行的方法 .虽然它不适用于实际用途,但C级扩展mpyw-junks/phpext-callee提供了匿名递归 without assigning variables .
在较新版本的PHP中,您可以这样做:
这可能会导致奇怪的行为 .