Возможно ли иметь функцию 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();
Это может привести к странному поведению.