4

This question is about some syntax a partner came across today and though we understand how it works, we don't understand why is it allowed (what is its use?).

Look at this snippet:

fun() -> ok end().

Without the last pair of parentheses this will produce something like:

#Fun<erl_eval.20.82930912>

But with them, the function is evaluated producing:

ok

My question is, why is that syntax allowed in Erlang ? why would I want to create a function just to call it immediately instead of just writing out its contents? is there any practical use to it ?

The only thing we could think about was introducing local variables inside the fun's body (but that would look ugly and unclear to me).

Please note that this other syntax is not allowed in Erlang, even though it follows the same concept of the former:

fun() -> fun() -> ok end end()().  

(It would mean: a function A that returns a function B. And I'm evaluating A (thus producing B) and then evaluating B to get 'ok').

Stephan Dollberg
  • 32,985
  • 16
  • 81
  • 107
Daniel
  • 21,933
  • 14
  • 72
  • 101
  • I don't know Erlang, but (I think) functions are first-class objects. That means that they can be arguments to functions, be assigned to variables, or even be return values themselves. It's super useful when you're doing something like sorting by a custom made function. See http://stackoverflow.com/questions/245192/what-are-first-class-objects – vroomfondel Sep 12 '13 at 21:19
  • About the last one, you might be wrong. At least my version of erlang works with this `fun() -> fun() -> ok end() end().` I mean that the statement is correct. – ipinak Sep 12 '13 at 21:23
  • @rogaos Yes, they're 1st-class objects in Erlang. But then why is the second syntax not allowed? (the fun returning the fun). – Daniel Sep 12 '13 at 21:24
  • @ipinak Note how the 2 pairs of parentheses are placed at the end of the second `end` of my version. – Daniel Sep 12 '13 at 21:26
  • @DWilches I didn't really understood your reply. – ipinak Sep 12 '13 at 21:31
  • @ipinak Sorry for not being clear. Look at my version of that code snippet: `fun() -> fun() -> ok end end()().` Note that at the end I have `()()` while in your version you have each `()` after its corresponding `end`. Like this: `fun() -> fun() -> ok end() end().` . In your case there is no issue because the outer function is not returning a function, it is returning `'ok'` already. – Daniel Sep 12 '13 at 21:31
  • @DWilches I noticed, but what you wrote does not run at all. That's why I wrote you the other one. – ipinak Sep 12 '13 at 21:34
  • @ipinak Oh yes, that is the question. Why is that syntax not allowed but the first one is. Because what I wrote: `fun() -> fun() -> ok end end()()` makes sense. – Daniel Sep 12 '13 at 21:36
  • Maybe parsing limitations. `(fun() -> fun () -> ok end end ())(). ` works, note the parentheses to scope funs – lud Sep 13 '13 at 17:16
  • arf, i should read answers before commenting – lud Sep 13 '13 at 17:16

2 Answers2

10

The syntax you mentioned is a natural outcome of Erlang's being functional.

In Erlang, functions are values (stored as closures).

The value of fun() -> ok end is a function, which takes nothing and returns ok. When we put parentheses after it, we are calling that function. Another way to demonstrate this is:

 > F = fun() -> ok end.  
 #Fun<erl_eval.20.80484245>
 > F().                  
 ok

The functions in the second example of yours need to be grouped properly in order for the parser to make sense of them.

As for your question -- "why this syntax is allowed", I'd have to say it's a natural outcome of functions being values in Erlang. This ability enables the functional style of programming. Here is an example:

 > lists:map(fun(X) -> X * 2 end, [1,2,3]).
 [2,4,6]

The above code is in essence this:

 > [fun(X) -> X * 2 end(1), fun(X) -> X * 2 end(2), fun(X) -> X * 2 end(3)].
 [2,4,6]

A "natural outcome" is just a natural outcome, it really doesn't have to be of any practical use. So, you will probably never see code like (fun() -> fun() -> ok end end())(). being used:)

hichris123
  • 10,145
  • 15
  • 56
  • 70
Ning
  • 2,850
  • 2
  • 16
  • 23
2

You typically wont't have much use for the syntax fun() -> ok end (). But it can be useful to do something like (find_right_fun()) (), which is basically the same thing - an expression that evaluates to a function.

Note that the Erlang parser requires you to specify the precedence using () to sort out the meaning of ()(), i.e. your second example should be (fun() -> fun() -> ok end end()) ().

johlo
  • 5,422
  • 1
  • 18
  • 32