Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing anonymous function as parameter to a function in Erlang?

Tags:

erlang

Erlang gives quite some emphasis on readability.

Pattern matching,list comprehensions are good tools to minimize your code without actually ruining the readability. However,oftentimes anonymous functions are passed in as function parameter in erlang.

for me it is annoying to read that.Is there any particular reason why this is done?

for exmple in general:

hhfuns:fold(fun(A,B) -> A + B end, 0, lists:seq(1,6)).
like image 913
HIRA THAKUR Avatar asked Nov 04 '14 05:11

HIRA THAKUR


2 Answers

You can handle this any way you like. The syntax can be annoying at first, but you will likely get used to it. In any case, you are trying to pass a value to a function, the same way you do any other parameter. If you keep this in mind you will realize you have three ways to do this.

Consider the following example module:

-module(funplay).
-export([external/1, internal/1, inline/1]).

apply_foo(Foo, Thingy) -> Foo(Thingy).

add_one(N) -> N + 1.

external(X) ->
    apply_foo(fun add_one/1, X).

internal(X) ->
    AddOne = fun(N) -> N + 1 end,
    apply_foo(AddOne, X).

inline(X) ->
    apply_foo(fun(N) -> N + 1 end, X).

I can't think of any better way to explain it than with the code above.

I prefer the external way if I know I'll be using the same thing a bunch of places (in which case, I really need to define the procedure, not re-write it anonymously everywhere). I prefer the internal way whenever I need to pass a non-trivial or multi-line condition to a function (just easier for me to read, and I hate indentation in arguments) or if I will need it more than once within the same function, and I prefer the inline way for trivial checks in something like a filter or fold.

like image 106
zxq9 Avatar answered Oct 23 '22 21:10

zxq9


Choosing the syntax is a matter of taste, or company coding rules, but what is interesting is the power of this feature. here is an example where I send the function in a message to an another node, which forward in turn to a list of process which finally execute it (note that I chose anonymous function, doing this I am sure that the receiving node will be able to execute the function):

start 2 nodes:

erl -sname node1
erl -sname node2

on node1, in the shell (needs R17 to work with this syntax):

Loop = fun Loop(X) -> receive                                             
{forward, Mess} -> lists:foreach(fun(Pid) -> Pid ! Mess end, X), Loop(X); 
stop -> ok                                                                
end                                                                       
end.

Proc = fun Proc(X) -> receive
{do,Fun} -> Y = Fun(X), Proc(Y);
stop -> ok                     
end                            
end.                           

L = [spawn(fun() -> Proc(0) end) || _ <- lists:seq(1,10)].

register(server,spawn(fun() -> Loop(L) end)).

on node2:

(node2@XXX)1>net_adm:ping(node1@XXX).                                                              
pong               
(node2@XXX)2> {server,node1@XXX} ! {forward,{do,fun(X) ->Self = self(), io:format("~p state is ~p~n",[Self,X]),X end}}.
{forward,{do,#Fun<erl_eval.6.90072148>}}
(node2@XXX)3> {server,node1@XXX} ! {forward,{do,fun(X) -> X + 1  end}}.                            
{forward,{do,#Fun<erl_eval.6.90072148>}}
(node2@XXX)4> {server,node1@XXX} ! {forward,{do,fun(X) ->Self = self(), io:format("~p state is ~p~n",[Self,X]),X end}}.
{forward,{do,#Fun<erl_eval.6.90072148>}}
(node2@XXX)4> 

the result on node1:

<0.42.0> state is 0   
<0.43.0> state is 0   
<0.44.0> state is 0   
<0.45.0> state is 0   
<0.46.0> state is 0   
<0.47.0> state is 0   
<0.48.0> state is 0   
<0.49.0> state is 0   
<0.50.0> state is 0   
<0.51.0> state is 0   
<0.43.0> state is 1   
<0.42.0> state is 1   
<0.44.0> state is 1   
<0.45.0> state is 1   
<0.46.0> state is 1   
<0.47.0> state is 1   
<0.48.0> state is 1   
<0.49.0> state is 1   
<0.50.0> state is 1   
<0.51.0> state is 1   
(node1@XXX)5> 
like image 41
Pascal Avatar answered Oct 23 '22 23:10

Pascal