2009-05-15 8 views
33

Estoy intentando escribir una diversión recursiva en una cáscara de Erlang, pero me siguen dando una excepción variable sin asignar:¿Cómo se escribe una diversión recursiva en Erlang?

1> Foo = fun(X) -> Foo(X) end. 
* 1: variable 'Foo' is unbound 

Esto probablemente es evidente, pero no estoy tratando de crear un bucle infinito! Este es solo un simple ejemplo del error que estoy recibiendo.

+2

"Diversiones con nombres": http: //www.erlang. org/eeps/eep-0037.html, que se fusionó en Erlang a finales de 2012. –

Respuesta

47

Puede hacerlo con un pequeño truco argumento:

1> Foo = fun(F, X) -> F(F, X) end. 
#Fun<erl_eval.12.113037538> 
2> Foo(Foo, a). 
<...infinite loop!> 

El truco aquí es enviar en la función como un argumento a sí mismo para permitir la recursividad.

manera alternativa de hacer que en un lanzamiento:

1> Foo = fun(X) -> Fun = fun(F,Y) -> F(F,Y) end, Fun(Fun,X) end. 
#Fun<erl_eval.6.13229925> 
2> Foo(a). 

Por ejemplo:

1> Foo = fun(Max) -> 
1>  Fun = fun(F, X) when X > Max -> []; 
1>    (F, X) -> [X | F(F, X+1)] 
1>   end, 
1>  Fun(Fun, 0) 
1> end. 
#Fun<erl_eval.6.13229925> 
2> Foo(10). 
[0,1,2,3,4,5,6,7,8,9,10] 

Desde OTP 17.0 no se nombran diversiones que hace la tarea mucho más fácil:

1> Perms = fun F([]) -> [[]]; F(L) -> [[H|T] || H <- L, T <- F(L--[H])] end.  
#Fun<erl_eval.30.54118792> 
2> Perms([a,b,c]). 
[[a,b,c],[a,c,b],[b,a,c],[b,c,a],[c,a,b],[c,b,a]] 
+2

No tengo experiencia con Erlang, pero me parece que los dos argumentos, a y Foo, deberían revertirse ... –

+0

¡Gracias! ¡Está arreglado ahora! –

+1

¿Esta respuesta augura el Y-combinator, como se menciona en otra respuesta aquí? – allyourcode

-1

Obviamente, Foo se asigna solo después de que se define la diversión, por lo que no se puede acceder desde él.

No creo que Erlang permita llamar a la función anónima desde sí mismo. Solo hazlo uno nombrado.

16

Alternativamente, puede usar el combinador Y. Y Combinator in Erlang explica.

+0

Aprender sobre el Y-combinator ha estado en mi lista de cosas para aprender durante mucho tiempo. Gracias por señalar el momento oportuno :). Para las personas que conocen Scheme, pensé que la siguiente página era útil: http://dangermouse.brynmawr.edu/cs245/ycomb_jim.html – allyourcode

+1

Tim, creo que esta respuesta podría haber sido mejor si hubieras mencionado brevemente qué es el Y-combinator acerca de. Probablemente habría aceptado esta respuesta si lo hubieras hecho. – allyourcode

+0

El enlace en la respuesta no funcionó para mí, pero encontré [parte 1] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-or.html) y [parte 2] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-part-2.html) de este recorrido por la implementación del combinador y en erlang extremadamente útil.Todavía me estoy volviendo loco, pero es un buen paso paso a paso como el de Scheme. – laindir

16

Después de Erlang 17, también puede utilizar la variante "Funs with names":

Foo = fun F(X) -> F(X) end. 

De esta manera es más fácil de entender que F es la propia función dentro de la definición. Además, Foo y F pueden ser la misma variable.

0

que tenían una necesidad de enviar rápidamente algunos paquetes a través de UDP para la prueba y así es como lo he hecho usando las muestras de arriba:

Sendtimes = fun F(0,Socket) -> ok; 
     F(Times,Socket) -> gen_udp:send(Socket, {127,0,0,1}, 5555, ["Message #:" ++ [Times]]), 
     F(Times-1,Socket) end. 
Cuestiones relacionadas