2009-05-15 5 views
33

Ich versuche, einen rekursive Spaß in einem Erlang-Shell zu schreiben, aber ich erhalte eine ungebundene Variable Ausnahme erhalten:Wie schreibt man einen Spaß, der in Erlang rekursiv ist?

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

Dies geht wahrscheinlich ohne zu sagen, aber ich versuche, nicht in eine Endlosschleife zu schaffen! Dies ist nur ein einfaches Beispiel für den Fehler, den ich bekomme.

+2

„Funs mit Namen“: http: //www.erlang. org/eeps/eep-0037.html, das Ende 2012 in Erlang zusammengeführt wurde. –

Antwort

47

Sie können es mit ein wenig Argument Trick:

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

Der Trick hier ist, um sich in der Funktion als Argument zu senden Rekursion zu ermöglichen.

Alternative, wie es in einem Shooting zu machen:

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

Zum Beispiel:

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] 

Seit OTP 17.0 dort Spaßt benannt, die die Aufgabe viel einfacher macht:

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

Ich habe keine Erfahrung mit Erlang, aber es scheint mir, dass die beiden Argumente a und Foo umgekehrt werden sollten ... –

+0

Danke! Es ist jetzt behoben! –

+1

Bezeichnet diese Antwort den Y-Kombinator, wie in einer anderen Antwort hier erwähnt? – allyourcode

-1

Offensichtlich wird Foo erst zugewiesen, nachdem der Spaß definiert wurde, so dass von dort nicht darauf zugegriffen werden kann.

Ich glaube nicht, dass Erlang erlaubt, die anonyme Funktion von sich selbst zu nennen. Mach es einfach zu einem Namen.

16

Alternativ können Sie den Y-Kombinator verwenden. Y Combinator in Erlang erklärt.

+0

Das Lernen über den Y-Kombinator steht seit langem auf meiner Liste. Danke für den Hinweis auf den günstigen Moment :). Für Leute, die Scheme kennen, dachte ich, die folgende Seite war nützlich: http://dangermouse.brynmawr.edu/cs245/ycomb_jim.html – allyourcode

+1

Tim, ich denke, diese Antwort hätte besser sein können, wenn Sie kurz erwähnt hätten, was der Y-Kombinator ist Über. Ich hätte diese Antwort wahrscheinlich akzeptiert, wenn Sie das getan hätten. – allyourcode

+0

Der Link in der Antwort funktionierte nicht für mich, aber ich fand [Teil 1] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-or.html) und [Teil 2] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-part-2.html) dieses Walk-Through zur Implementierung des y-Kombinators in Erlang ist äußerst hilfreich.Ich wickle immer noch meinen Kopf herum, aber es ist ein schöner Schritt für Schritt, genau wie der für Schema oben. – laindir

16

Nach Erlang 17, können Sie auch die "Funs with names" Variante verwenden:

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

Auf diese Weise ist es leichter zu verstehen, dass F ist die Funktion selbst innerhalb der Definition. Auch Foo und F können die gleiche Variable sein.

0

hatte ich eine Notwendigkeit, schnell ein paar Pakete über UDP für den Test schicken und hier ist, wie ich es die Proben oben mit getan haben:

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.