Sunday, October 27, 2013

Erlang Function Call Precedence

My goal is to lazy evaluate results. I want to get the nth element after performing some operations on a list of elements and I don't want to actually perform the computation unless it is required. I also want to show how to call the returned value which is a function immediately.

Generate a list with sequence 1 to 5.
1> lists:seq(1, 5).
An anonymous function that returns the double. This as such does nothing.
2> fun(X) -> 2*X end. 
An anonymous function which returns a function which when called returns the double.
3> fun(X) -> (fun() -> 2*X end) end.
We can also write this without brackets
4> fun(X) -> fun() -> 2*X end end.
Call the above function for each element in the list. We will use map for that. Let's assign the resultant list to a variable L.
5> L = lists:map(fun(X) -> (fun() -> 2*X end) end, lists:seq(1, 5)).
We know the function returns another function and results are not evaluated until we call the returned function.
Say, instead of doubling operation, we perform sightly heavier computations. Here we are not performing the computation. We intend to perform the operation only when the result is required.

Now let's get, say the 3rd element from the above list.
6> lists:nth(3, L).
But I want to get the computed result. So I have to call the returned function. Now this is where it get slightly tricky. We can call the returned function by assigning it to a variable and calling it or call it directly.
7> F = lists:nth(3, L).
8> F().
To call the returned function directly, we have to wrap the whole expression in parenthesis and then call.
9> (lists:nth(3, L))().
We cannot call it like lists:nth(3, L)() which will produce an error 1: syntax error before: '(. It is due to the precedence rules in the Erlang grammar.

Here we are able to call it without parenthesis.
10> fun(X) -> 2*X end (3).
In this case, it works with parenthesis as well.
11> (fun(X) -> 2*X end)(2).