Рекурсивные анонимные функции PHP
возможно ли иметь функцию PHP, которая является одновременно рекурсивной и анонимной? Это моя попытка заставить его работать, но он не проходит в имя функции.
$factorial = function( $n ) use ( $factorial ) {
if( $n <= 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
Я также знаю, что это плохой способ реализации факториала, это просто пример.
4 ответов:
для того, чтобы он работал, вам нужно передать $factorial в качестве ссылки
$factorial = function( $n ) use ( &$factorial ) { if( $n == 1 ) return 1; return $factorial( $n - 1 ) * $n; }; print $factorial( 5 );
Я знаю, что это не может быть простой подход, но я узнал о технике под названием "исправить" из функциональных языков. Элемент
fixфункция от Haskell известна более широко как Y combinator, который является одним из самых известных комбинаторы с фиксированной точкой.фиксированная точка-это значение, которое не изменяется функцией: фиксированная точка функции f любой x такие, что x = f(х). Один комбинатор с фиксированной точкой y - это функция, которая возвращает неподвижную точку для любой функции f. Поскольку Г(Е) является фиксированной точкой F, то есть Г(ф) = ф(г(Ф)).
по существу, Y-комбинатор создает новую функцию, которая принимает все аргументы оригинала, плюс дополнительный аргумент, который является рекурсивной функцией. Как это работает, более очевидно, используя нотацию Карри. Вместо того, чтобы писать аргументы в скобках (
f(x,y,...)), напишите их после функции:f x 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 );обратите внимание, что это почти то же самое, что и простые решения закрытия, которые другие опубликовали, но функция
fixсоздает закрытие для вас. Комбинаторы с фиксированной точкой немного сложнее, чем при использовании замыкания, но более общие, и имеют другие пользы. В то время как метод закрытия более подходит для PHP (который не является ужасно функциональным языком), исходная проблема является скорее упражнением, чем для производства, поэтому Y-комбинатор является жизнеспособным подходом.
хотя это не для практического использования, расширение 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)
в новых версиях PHP вы можете сделать это:
$x = function($depth = 0) { if($depth++) return; $this($depth); echo "hi\n"; }; $x = $x->bindTo($x); $x();Это может привести к странному поведению.
Comments