Est-il possible d'avoir une fonction PHP à la fois récursive et anonyme? C'est ma tentative pour le faire fonctionner, mais il ne transmet pas 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, c'est juste un exemple.
global $factorial
?print $factorial( 0);
Réponses:
Pour que cela fonctionne, vous devez passer $ factorial comme référence
la source
&
est sans valeur. Tout&
est par référence. Les "objets" ne sont pas des valeurs en PHP5 et ne peuvent pas être attribués ou transmis. Vous avez affaire à une variable dont la valeur est une référence d'objet. Comme toutes les variables, il peut être capturé par valeur ou par référence, selon qu'il existe un&
.$factorial
sera modifié avant l'appel de la fonction et il peut en résulter un comportement étrange.Je sais que ce n'est peut-être pas une approche simple, mais j'ai appris une technique appelée «correction» à partir de langages fonctionnels. La
fix
fonction de Haskell est plus généralement connue sous le nom de combinateur Y , qui est l'un des combinateurs à point fixe les plus connus .Un point fixe est une valeur inchangée par une fonction: un point fixe d'une fonction f est tout 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 combinateur Y 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 des arguments entre parenthèses (
f(x,y,...)
), les écrire après la fonction:f x y ...
. Le combinateur Y est défini commeY f = f (Y f)
; ou, avec un seul argument pour la fonction récursive,Y f x = f (Y f) x
.Depuis PHP ne curry pas automatiquement les fonctions, c'est un peu un hack pour faire
fix
fonctionner, mais je pense que c'est intéressant.Notez que c'est presque la même chose que les solutions de fermeture simples que d'autres ont publiées, mais la fonction
fix
crée la fermeture pour vous. Les combinateurs à virgule fixe sont légèrement plus complexes que l'utilisation d'une fermeture, mais sont plus généraux et ont d'autres utilisations. Alors que la méthode de fermeture convient mieux à PHP (qui n'est pas un langage terriblement fonctionnel), le problème d'origine est plus un exercice que pour la production, donc le combinateur Y est une approche viable.la source
call_user_func_array()
c'est lent comme Noël.call_user_func_array
.array_unshift( $args, fix($func) );
? Args est déjà chargé avec les paramètres, et la récursivité réelle est effectuée par call_user_func_array (), alors que fait cette ligne?Bien que ce ne soit pas pour une utilisation pratique, l'extension de niveau C mpyw-junks / phpext-callee fournit une récursivité anonyme sans affecter de variables .
la source
Dans les versions plus récentes de PHP, vous pouvez le faire:
Cela peut potentiellement conduire à un comportement étrange.
la source
Vous pouvez utiliser Y Combinator en PHP 7.1+ comme ci-dessous:
Jouez avec: https://3v4l.org/7AUn2
Codes source de: https://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php
la source
Avec une classe anonyme (PHP 7+), sans définir de variable:
la source