Now, let me tell you what I’ve found…

It all boils down to what an anonymous function actually represents in the different contexts. To understand that we have a very useful function: erlang:fun_info/1. Given an anonymous function, fun_info will tell you all you need to know to evaluate it. I added an exported function to our hello module so I can retrieve an anonymous function from it. Look…

So now I can compare the fun_info from all of our funs. Let’s start with this new one:

7> erlang:fun_info(hello:f()).

[{pid,<0.74.0>},

{module,hello},

{new_index,0},

{new_uniq,<<29,221,195,226,62,18,74,8,213,112,251,233,

174,128,161,226>>},

{index,0},

{uniq,15658527},

{name,’-f/0-fun-0-’},

{arity,0},

{env,[]},

{type,local}]

8> hello:f().

#Fun<hello.0.15658527>

I highlighted the important pieces. As you can see, the module in charge of this fun’s code is hello, it’s index is 0 and it’s uniq is 15658527, therefore the fun is called #Fun<hello.0.15658527>. But that’s not all, it also has an atom as name: ‘-f/0-fun-0-’. And you can totally use that name, for instance to trace the function with redbug:

2> X = hello:f().

#Fun<hello.0.15658527>

3> redbug:start(“hello:’-f/0-fun-0-’”).

{33,1}

4> X().

“Hello, world!” % 14:02:16 <0.41.0>({erlang,apply,2})

% hello:’-f/0-fun-0-’()

5>

It looks pretty much like any other non exported function, right? Hold on to that thought, we’ll come back to it in a minute…

Now, let’s see how our shell-defined funs look like:

5> F = fun() -> “Hello, world!” end.

#Fun<erl_eval.20.50752066>

6> erlang:fun_info(F).

[{pid,<0.41.0>},

{module,erl_eval},

{new_index,20},

{new_uniq,<<96,205,72,68,75,104,221,132,114,190,222,211,

56,153,90,202>>},

{index,20},

{uniq,50752066},

{name,’-expr/5-fun-3-’},

{arity,0},

{env,[{[],

{eval,#Fun<shell.21.83096281>},

{value,#Fun<shell.5.83096281>},

[{clause,1,[],[],[{string,1,”Hello, world!”}]}]}]},

{type,local}]

As you can see, in this case the fun lives in erl_eval. That’s odd, right? We never edited that module, did we? The index and uniq matches the name again, which what we would’ve expected. But the key part is the env. There you have the AST for our fun. That is telling us the fun which we have in F is not exactly the fun we wrote. It’s an anonymous function contained in the erl_eval module that evaluates the AST that we defined above. Do you want to see that anonymous function? I did! And given its name (-expr/5-fun-3-) I could infer that we’re talking about this one. And bonus track if you follow that link: you can find how many args can a fun have if you define it in the shell ;)

Ok, but then why can I assign a variable twice to the same fun in the shell in different expressions, but not in the same expression? fun_info to the rescue, again!!

7> F = fun() -> “Hello, world!” end,

7> G = fun() -> “Hello, world!” end.

#Fun<erl_eval.20.50752066>

8> erlang:fun_info(G).

[{pid,<0.41.0>},

{module,erl_eval},

{new_index,20},

{new_uniq,<<96,205,72,68,75,104,221,132,114,190,222,211,

56,153,90,202>>},

{index,20},

{uniq,50752066},

{name,’-expr/5-fun-3-’},

{arity,0},

{env,[{[],

{eval,#Fun<shell.21.83096281>},

{value,#Fun<shell.5.83096281>},

[{clause,2,[],[],[{string,2,”Hello, world!”}]}]}]},

{type,local}]

As you can see, the AST is different this time, since our function is in the second clause of the expression. Therefore, the fun is different, because the env is obviously part of what defines an anonymous function.