2009-05-15 11 views
33

Sto cercando di scrivere un divertente ricorsiva in un guscio Erlang, ma io continuo a ricevere un'eccezione variabile non legato:Come scrivi un divertimento che è ricorsivo in Erlang?

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

Questo va probabilmente senza dire, ma io non sto cercando di creare un ciclo infinito! Questo è solo un semplice esempio dell'errore che sto ottenendo.

+2

"Funs con nomi": http: //www.erlang. org/eeps/eep-0037.html, che è stato fuso in Erlang alla fine del 2012. –

risposta

47

È possibile farlo con un piccolo trucco argomento:

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

Il trucco è quello di inviare nella funzione come argomento a se stessa per consentire la ricorsione.

modo alternativo per farlo in uno shoot:

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

Ad esempio:

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] 

Dal OTP 17.0 ci sono chiamati divertimenti che rende il compito molto più facile:

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

Non ho esperienza con Erlang, ma mi sembra che i due argomenti a e Foo debbano essere invertiti ... –

+0

Grazie! È ora riparato! –

+1

Questa risposta fa presagire il combinatore Y, come menzionato in un'altra risposta qui? – allyourcode

-1

Ovviamente, Foo viene assegnato solo dopo che il divertimento è stato definito, quindi non è possibile accedervi dall'interno.

Non credo che Erlang consenta di chiamare la funzione anonima da sé. Falla solo nominare.

16

In alternativa, è possibile utilizzare il combinatore Y. Y Combinator in Erlang spiega.

+0

L'apprendimento del combinatore Y è stato nel mio elenco di cose da imparare per molto tempo. Grazie per aver segnalato il momento opportuno :). Per le persone che conoscono Scheme, ho pensato che la seguente pagina fosse utile: http://dangermouse.brynmawr.edu/cs245/ycomb_jim.html – allyourcode

+1

Tim, penso che questa risposta avrebbe potuto essere migliore se avessi brevemente menzionato che cos'è il combinatore Y di. Probabilmente avrei accettato questa risposta se l'avessi fatto. – allyourcode

+0

Il collegamento nella risposta non ha funzionato per me, ma ho trovato [parte 1] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-or.html) e [parte 2] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-part-2.html) di questo approccio sull'implementazione del combinatore y in erlang estremamente utile.Sto ancora avvolgendo la testa, ma è un bel passo dopo passo, proprio come quello per Schema sopra. – laindir

16

Dopo Erlang 17, è anche possibile utilizzare il "Funs with names" variante:

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

In questo modo è più facile comprendere che F è la stessa funzione nella definizione. Inoltre, Foo e F possono essere la stessa variabile.

0

ho avuto la necessità di inviare rapidamente alcuni pacchetti UDP per il test e ecco come ho fatto con i campioni di cui sopra:

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.