Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang: how can I reference an anonymous function from within the body?

Tags:

erlang

In Erlang is there a way reference the currently executing function)?

That would be useful to spawn an infinite loop:

spawn(fun() -> do_something, this_fun() end)

In JavaScript arguments.callee does just that, see the specification on MDC.

Edit to answer a 'why would you do that': mostly curiosity; it is also useful to define a timer when prorotyping:

Self = self(),
spawn(fun() -> Self ! wake_up, receive after 1000 -> nil end, this_fun() end),
%% ...
like image 421
Matteo Caprari Avatar asked Jul 24 '09 19:07

Matteo Caprari


People also ask

How do you call an anonymous function?

Anonymous Function is a function that does not have any name associated with it. Normally we use the function keyword before the function name to define a function in JavaScript, however, in anonymous functions in JavaScript, we use only the function keyword without the function name.

What is fun () in Erlang?

Advertisements. Funs are used to define anonymous functions in Erlang.

Which command can be called directly by an anonymous function?

These functions are called anonymous because they are not declared in the standard manner by using the def keyword. You can use the lambda keyword to create small anonymous functions. Lambda forms can take any number of arguments but return just one value in the form of an expression.

How and when do you use anonymous functions?

Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function.


2 Answers

In Erlang/OTP 17.0-rc1, you can use a named fun for that:

1> Self = self(),
1> Fun = fun ThisFun() ->
             Self ! wake_up,
             receive after 1000 -> nil end,
             ThisFun()
         end.
#Fun<erl_eval.44.71889879>
2> spawn(Fun).
<0.35.0>
3> flush().
Shell got wake_up
Shell got wake_up
Shell got wake_up
ok

In earlier versions, there is no way to do exactly that. You could pass the function itself as an argument:

Self = self(),
Fun = fun(ThisFun) ->
          Self ! wake_up,
          receive after 1000 -> nil end,
          ThisFun(ThisFun)
      end
spawn(fun() -> Fun(Fun) end),
%% ...
like image 149
legoscia Avatar answered Sep 20 '22 17:09

legoscia


If you feel like twisting things a little bit:

Y = fun(M,B) -> G = fun(F) -> M(fun() -> (F(F))() end, B) end, G(G) end.
spawn(Y(fun(F, ParentPid) -> fun() -> ParentPid ! wake_up, receive after 1000 -> ok end, F() end end, self())).

Flush the messages couple times to see the result:

flush().

Of course, Y is more useful if you put it in some sort of library. Also you can find this post on Y Combinators: http://bc.tech.coop/blog/070611.html quite interesting

like image 39
zakovyrya Avatar answered Sep 21 '22 17:09

zakovyrya