Анонимные рекурсивные функции PHP

Возможно ли иметь функцию 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 известна в более общем смысле как комбинатор Y , который является одним из наиболее известных комбинаторов с фиксированной точкой .

Фиксированная точка – это значение, неизменное функцией: неподвижная точка функции f является любой x такой, что x = f (x). Комбинатор с фиксированной точкой y является функцией, которая возвращает неподвижную точку для любой функции f. Так как y (f) – фиксированная точка f, то y (f) = f (y (f)).

По сути, комбинатор Y создает новую функцию, которая принимает все аргументы оригинала плюс дополнительный аргумент, являющийся рекурсивной функцией. Как это работает, более очевидно, используя кардиотрансляцию. Вместо записи аргументов в круглых скобках ( f(x,y,...) ), напишите их после функции: fxy ... Комбинатор Y определяется как Y f = f (Y f) ; или, с единственным аргументом для рекурсированной функции, Y fx = 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 обеспечивает анонимную рекурсию без назначения переменных .

 <?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(); 

Это может привести к странному поведению.