web-dev-qa-db-fra.com

Anonyme récursif PHP les fonctions

Est-il possible d'avoir une fonction PHP à la fois récursive et anonyme? Ceci est ma tentative de le faire fonctionner, mais il ne passe pas dans le nom de la fonction.

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

Je suis également conscient que c'est une mauvaise façon de mettre en œuvre factorielle, ce n'est qu'un exemple.

177
Kendall Hopkins

Pour que cela fonctionne, vous devez utiliser $ factorial comme référence.

$factorial = function( $n ) use ( &$factorial ) {
    if( $n == 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
324
Derek H

Je sais que cette approche n’est peut-être pas simple, mais j’ai découvert une technique appelée "réparer" à partir de langages fonctionnels. La fonction fix de Haskell est connue plus généralement sous le nom de Y Combinator , qui est l’un des combinateurs les plus connus de points fixes

Un point fixe est une valeur inchangée par une fonction: un point fixe d'une fonction f est quelconque x tel que x = f (x). Un combinateur à point fixe y est une fonction qui renvoie un point fixe pour toute fonction f. Puisque y(f) est un point fixe de f, nous avons y (f) = f (y (f)).

Essentiellement, le Y Combinator crée une nouvelle fonction qui prend tous les arguments de l’original, plus un argument supplémentaire qui est la fonction récursive. Comment cela fonctionne est plus évident en utilisant la notation au curry. Au lieu d'écrire les arguments entre parenthèses (f(x,y,...)), écrivez-les après la fonction: f x y .... Le Y Combinator est défini comme Y f = f (Y f); ou, avec un seul argument pour la fonction récursive, Y f x = f (Y f) x.

Puisque PHP ne fonctionne pas automatiquement curry , c'est un peu un bidouillage de faire fonctionner fix, mais je pense que c'est intéressant.

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

Notez que ceci est presque identique aux solutions de fermeture simples publiées par d’autres, mais la fonction fix crée la fermeture pour vous. Les combinateurs à points fixes sont légèrement plus complexes que l'utilisation d'une fermeture, mais sont plus généraux et ont d'autres utilisations. Bien que la méthode de fermeture convienne mieux à PHP (qui n'est pas un langage très fonctionnel), le problème initial étant davantage un exercice que pour la production, le Y Combinator est une approche viable.

24
Kendall Hopkins

Bien que ce ne soit pas pour un usage pratique, l’extension de niveau C mpyw-junks/phpext-callee fournit une récursivité anonyme sans affecter de variables.

<?php

var_dump((function ($n) {
    return $n < 2 ? 1 : $n * callee()($n - 1);
})(5));

// 5! = 5 * 4 * 3 * 2 * 1 = int(120)
4
mpyw

Dans les nouvelles versions de PHP, vous pouvez le faire:

$x = function($depth = 0) {
    if($depth++)
        return;

    $this($depth);
    echo "hi\n";
};
$x = $x->bindTo($x);
$x();

Cela peut potentiellement conduire à un comportement étrange.

0
jgmjgm

Vous pouvez utiliser Y Combinator dans PHP 7.1+ comme ci-dessous:

function Y
($le)
{return
    (function ($f) 
     {return
        $f($f);
     })(function ($f) use ($le) 
        {return
            $le(function ($x) use ($f) 
                {return
                    $f($f)($x);
                });
        });
}

$le =
function ($factorial)
{return
    function
    ($n) use ($factorial)
    {return
        $n < 2 ? $n
        : $n * $factorial($n - 1);
    };
};

$factorial = Y($le);

echo $factorial(1) . PHP_EOL; // 1
echo $factorial(2) . PHP_EOL; // 2
echo $factorial(5) . PHP_EOL; // 120

Jouez avec: https://3v4l.org/7AUn2

Codes source de: https://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php

0
Lei Fan