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



возможно ли иметь функцию PHP, которая является одновременно рекурсивной и анонимной? Это моя попытка заставить его работать, но он не проходит в имя функции.



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


Я также знаю, что это плохой способ реализации факториала, это просто пример.

606   4  

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

    Ничего не найдено.