recursividad - Funciones PHP recursivas anónimas
manejo de funciones en php (4)
¿Es posible tener una función PHP recursiva y anónima? Este es mi intento de hacer que funcione, pero no pasa el nombre de la función.
$factorial = function( $n ) use ( $factorial ) {
if( $n <= 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
También soy consciente de que esta es una mala forma de implementar factorial, es solo un ejemplo.
Aunque no es para uso práctico, la extensión de nivel C mpyw-junks/phpext-callee proporciona recursión anónima sin asignar variables .
<?php
var_dump((function ($n) {
return $n < 2 ? 1 : $n * callee()($n - 1);
})(5));
// 5! = 5 * 4 * 3 * 2 * 1 = int(120)
En las versiones más nuevas de PHP puedes hacer esto:
$x = function($depth = 0) {
if($depth++)
return;
$this($depth);
echo "hi/n";
};
$x = $x->bindTo($x);
$x();
Esto puede conducir a un comportamiento extraño.
Para que funcione, debe pasar $ factorial como referencia
$factorial = function( $n ) use ( &$factorial ) {
if( $n == 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
Sé que esto podría no ser un enfoque simple, pero aprendí sobre una técnica llamada "fix" de los lenguajes funcionales. La función de fix
de Haskell se conoce más generalmente como el combinador Y , que es uno de los combinadores de punto fijo más conocidos.
Un punto fijo es un valor que no cambia con una función: un punto fijo de una función f es cualquier x tal que x = f (x). Un combinador de punto fijo y es una función que devuelve un punto fijo para cualquier función f. Como y (f) es un punto fijo de f, tenemos y (f) = f (y (f)).
Esencialmente, el combinador Y crea una nueva función que toma todos los argumentos del original, más un argumento adicional que es la función recursiva. Cómo funciona esto es más obvio usando la notación al curry. En lugar de escribir argumentos entre paréntesis ( f(x,y,...)
), escríbalos después de la función: fxy ...
El combinador Y se define como Y f = f (Y f)
; o, con un único argumento para la función recursada, Y fx = f (Y f) x
.
Como PHP no curry automáticamente curry funciones, es un poco complicado hacer que la fix
funcione, pero creo que es interesante.
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 );
Tenga en cuenta que esto es casi lo mismo que las soluciones de cierre simples que otros han publicado, pero la fix
función crea el cierre para usted. Los combinadores de punto fijo son un poco más complejos que usar un cierre, pero son más generales y tienen otros usos. Si bien el método de cierre es más adecuado para PHP (que no es un lenguaje terriblemente funcional), el problema original es más un ejercicio que para la producción, por lo que el combinador Y es un enfoque viable.