Sei que essa pode não ser uma abordagem simples, mas aprendi sobre uma técnica chamada "correção" em linguagens funcionais. A fix
função de Haskell é conhecida mais geralmente como o combinador Y , que é um dos combinadores de ponto fixo mais conhecidos .
Um ponto fixo é um valor inalterado por uma função: um ponto fixo de uma função f é qualquer x tal que x = f (x). Um combinador de ponto fixo y é uma função que retorna um ponto fixo para qualquer função f. Como y (f) é um ponto fixo de f, temos y (f) = f (y (f)).
Essencialmente, o combinador Y cria uma nova função que aceita todos os argumentos do original, além de um argumento adicional que é a função recursiva. Como isso funciona é mais óbvio usando a notação ao curry. Em vez de escrever argumentos entre parênteses ( f(x,y,...)
), escreva-os após a função: f x y ...
. O combinador Y é definido como Y f = f (Y f)
; ou, com um único argumento para a função recorrente Y f x = f (Y f) x
,.
Desde o PHP não automaticamente caril funções, é um bocado de um hack para fazer fix
o trabalho, mas eu acho que é interessante.
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 );
Observe que isso é quase o mesmo que as soluções simples de fechamento postadas por outras pessoas, mas a função fix
cria o fechamento para você. Os combinadores de ponto fixo são um pouco mais complexos do que usar um fechamento, mas são mais gerais e têm outros usos. Embora o método de fechamento seja mais adequado para PHP (que não é uma linguagem extremamente funcional), o problema original é mais um exercício do que para produção, portanto o combinador Y é uma abordagem viável.
global $factorial
?