The following function,
double([H|T]) -> [2*H|double(T)];
double([]) -> [].
Hence, the argument entered as input is doubled as follows:
> double([1,2,3,4]). [2,4,6,8]
The following function,
add_one([H|T]) -> [H+1|add_one(T)];
add_one([]) -> [].
The functions
The functions
double(L) -> map(fun(X) -> 2*X end, L).
add_one(L) -> map(fun(X) -> 1 + X end, L).
The process of abstracting out the common features of a number of different programs is called procedural abstraction. Procedural abstraction can be used to write several different functions that have a similar structure, but differ in some minor detail. This is done as follows:
This section illustrates procedural abstraction. Initially, the following two examples are written as conventional functions.
This function prints all elements of a list onto a stream:
print_list(Stream, [H|T]) ->
io:format(Stream, "~p~n", [H]),
print_list(Stream, T);
print_list(Stream, []) ->
true.
This function broadcasts a message to a list of processes:
broadcast(Msg, [Pid|Pids]) ->
Pid ! Msg,
broadcast(Msg, Pids);
broadcast(_, []) ->
true.
These two functions have a similar structure. They both iterate over a list and do something to each element in the list. The "something" is passed on as an extra argument to the function that does this.
The function
Using the function
foreach(fun(H) -> io:format(S, "~p~n",[H]) end, L)
Using the function
foreach(fun(Pid) -> Pid ! M end, L)
Funs are written with the following syntax:
F = fun (Arg1, Arg2, ... ArgN) ->
...
end
This creates an anonymous function of
Another function,
F = fun FunctionName/Arity
With this form of function reference, the function that is referred to does not need to be exported from the module.
It is also possible to refer to a function defined in a different module, with the following syntax:
F = fun Module:FunctionName/Arity
In this case, the function must be exported from the module in question.
The following program illustrates the different ways of creating funs:
The fun
F(Arg1, Arg2, ..., Argn)
To check whether a term is a fun, use the test
Example:
f(F, Args) when is_function(F) ->
apply(F, Args);
f(N, _) when is_integer(N) ->
N.
Funs are a distinct type. The BIFs
The scope rules for variables that occur in funs are as follows:
The following examples illustrate these rules:
print_list(File, List) ->
{ok, Stream} = file:open(File, write),
foreach(fun(X) -> io:format(Stream,"~p~n",[X]) end, List),
file:close(Stream).
Here, the variable
As any variable that occurs in the head of a fun is considered a new variable, it is equally valid to write as follows:
print_list(File, List) ->
{ok, Stream} = file:open(File, write),
foreach(fun(File) ->
io:format(Stream,"~p~n",[File])
end, List),
file:close(Stream).
Here,
./FileName.erl:Line: Warning: variable 'File'
shadowed in 'fun'
This indicates that the variable
The rules for importing variables into a fun has the consequence
that certain pattern matching operations must be moved into
guard expressions and cannot be written in the head of the fun.
For example, you might write the following code if you intend
the first clause of
f(...) ->
Y = ...
map(fun(X) when X == Y ->
;
(_) ->
...
end, ...)
...
instead of writng the following code:
f(...) ->
Y = ...
map(fun(Y) ->
;
(_) ->
...
end, ...)
...
The following examples show a dialogue with the Erlang shell.
All the higher order functions discussed are exported from
the module
It returns the list obtained by applying the function to every argument in the list.
When a new fun is defined in the shell, the value of the fun
is printed as
> Double = fun(X) -> 2 * X end. #Fun<erl_eval.6.72228031> > lists:map(Double, [1,2,3,4,5]). [2,4,6,8,10]
A predicate is a function that returns
A predicate
> Big = fun(X) -> if X > 10 -> true; true -> false end end. #Fun<erl_eval.6.72228031> > lists:any(Big, [1,2,3,4]). false > lists:any(Big, [1,2,3,12,5]). true
It is
> lists:all(Big, [1,2,3,4,12,6]). false > lists:all(Big, [12,13,14,15]). true
The function is applied to each argument in the list.
> lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]). 1 2 3 4 ok
The function is called with two arguments. The first argument is the successive elements in the list. The second argument is the accumulator. The function must return a new accumulator, which is used the next time the function is called.
If you have a list of lists
> L = ["I","like","Erlang"]. ["I","like","Erlang"] 10> lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L). 11
L = ["I","like","Erlang"],
Sum = 0,
while( L != []){
Sum += length(head(L)),
L = tail(L)
end
The following example shows how to change all letters in
First the change to upper case:
> Upcase = fun(X) when $a =< X, X =< $z -> X + $A - $a; (X) -> X end. #Fun<erl_eval.6.72228031> > Upcase_word = fun(X) -> lists:map(Upcase, X) end. #Fun<erl_eval.6.72228031> > Upcase_word("Erlang"). "ERLANG" > lists:map(Upcase_word, L). ["I","LIKE","ERLANG"]
Now, the fold and the map can be done at the same time:
> lists:mapfoldl(fun(Word, Sum) -> {Upcase_word(Word), Sum + length(Word)} end, 0, L). {["I","LIKE","ERLANG"],11}
> lists:filter(Big, [500,12,2,45,6,7]). [500,12,45]
Combining maps and filters enables writing of very succinct
code. For example, to define a set difference
function
diff(L1, L2) ->
filter(fun(X) -> not member(X, L2) end, L1).
This gives the list of all elements in L1 that are not contained in L2.
The AND intersection of the list
intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).
> lists:takewhile(Big, [200,500,45,5,3,45,6]). [200,500,45]
> lists:dropwhile(Big, [200,500,45,5,3,45,6]). [5,3,45,6]
> lists:splitwith(Big, [200,500,45,5,3,45,6]). {[200,500,45],[5,3,45,6]}
So far, only functions that take funs as arguments have been described. More powerful functions, that themselves return funs, can also be written. The following examples illustrate these type of functions.
> Adder = fun(X) -> fun(Y) -> X + Y end end. #Fun<erl_eval.6.72228031> > Add6 = Adder(6). #Fun<erl_eval.6.72228031> > Add6(10). 16
The idea is to write something like:
-module(lazy).
-export([ints_from/1]).
ints_from(N) ->
fun() ->
[N|ints_from(N+1)]
end.
Then proceed as follows:
> XX = lazy:ints_from(1). #Fun<lazy.0.29874839> > XX(). [1|#Fun<lazy.0.29874839>] > hd(XX()). 1 > Y = tl(XX()). #Fun<lazy.0.29874839> > hd(Y()). 2
And so on. This is an example of "lazy embedding".
The following examples show parsers of the following type:
Parser(Toks) -> {ok, Tree, Toks1} | fail
An unsuccessful parse returns
The following example illustrates a simple, functional parser that parses the grammar:
(a | b) & (c | d)
The following code defines a function
This function can be used as follows:
> P1 = funparse:pconst(a). #Fun<funparse.0.22674075> > P1([a,b,c]). {ok,{const,a},[b,c]} > P1([x,y,z]). fail
Next, the two higher order functions
First
Given a parser
The original problem was to parse the grammar
The following code adds a parser interface to the grammar:
The parser can be tested as follows:
> funparse:parse([a,c]). {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} > funparse:parse([a,d]). {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} > funparse:parse([b,c]). {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} > funparse:parse([b,d]). {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} > funparse:parse([a,b]). fail