2009-05-15 6 views
33

Je suis en train d'écrire un amusement récursive dans une coquille Erlang, mais je continue à obtenir une exception variable non:Comment écrivez-vous un jeu récursif à Erlang?

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

Cela va probablement sans dire, mais je ne suis pas d'essayer de créer une boucle infinie! Ceci est juste un exemple simple de l'erreur que je reçois.

+2

« Funs avec les noms »: http: //www.erlang. org/eeps/eep-0037.html, qui a été fusionné en Erlang fin 2012. –

Répondre

47

Vous pouvez le faire avec un petit truc argument:

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

L'astuce est d'envoyer ici dans la fonction comme argument pour lui-même pour permettre récursivité.

autre façon de le faire dans un tournage:

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

Par exemple:

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] 

Depuis OTP 17.0 il existe des noms funs ce qui rend la tâche beaucoup plus 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

Je n'ai aucune expérience avec Erlang, mais il me semble que les deux arguments a et Foo devraient être inversés ... –

+0

Merci! C'est réparé maintenant! –

+1

Est-ce que cette réponse présage le Y-combinator, comme mentionné dans une autre réponse ici? – allyourcode

-1

Évidemment, Foo est assigné seulement après que l'amusement est défini, ainsi il ne peut pas être accédé de l'intérieur.

Je ne pense pas que Erlang permet d'appeler la fonction anonyme de lui-même. Juste en faire un nom.

16

Vous pouvez également utiliser le combinateur Y. Y Combinator in Erlang explique.

+0

Apprendre sur le combinateur Y a été sur ma liste de choses à apprendre depuis longtemps. Merci d'avoir souligné le moment opportun :). Pour les personnes qui connaissent Scheme, j'ai trouvé que la page suivante était utile: http://dangermouse.brynmawr.edu/cs245/ycomb_jim.html – allyourcode

+1

Tim, je pense que cette réponse aurait pu être meilleure si vous aviez brièvement mentionné ce qu'est le Y-combinator sur. J'aurais probablement accepté cette réponse si vous l'aviez fait. – allyourcode

+0

Le lien dans la réponse n'a pas fonctionné pour moi, mais j'ai trouvé [partie 1] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-or.html) et [partie 2] (http://bytecrafter.blogspot.com/2010/01/deriving-y-combinator-in-erlang-part-2.html) de ce passage à travers la mise en œuvre du combinateur y dans erlang extrêmement utile.J'enveloppe toujours ma tête, mais c'est une belle étape, comme celle de Scheme ci-dessus. – laindir

16

Après 17 Erlang, vous pouvez également utiliser la variante "Funs with names":

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

De cette façon, il est plus facile de comprendre que F est la fonction elle-même dans la définition. En outre, Foo et F peuvent être la même variable.

0

J'ai eu besoin d'envoyer rapidement des paquets sur UDP pour tester et voici comment je l'ai fait à l'aide des échantillons ci-dessus:

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.