Pattern matching in function, case and receive-clauses are optimized by the compiler. In most cases, there is nothing to gain by rearranging clauses.
A function can be called in a number of ways and the cost differs a lot. Which kind of call to use depends on the situation. Below follows a table with the available alternatives and their relative cost.
![]() |
The figures shown as relative cost is highly dependent on the implementation and will vary between versions and platform. The order from lowest to highest cost will however be stable and is very useful to be aware of. |
Type of call | Example |
Relative cost (5.4) |
Local call |
foo()
|
1.00 |
External call |
m:foo()
|
1.08 |
Fun call |
Fun = fun(X) -> X + 1 end, Fun(2)
|
2.79 |
Apply fun |
Fun = fun(X) -> X + 1 end, apply(Fun,[2])
|
3.54 |
Implicit apply |
M:Foo()
|
7.76 |
Apply MFA/3 |
apply(M, Foo, [])
|
8.21 |
Apply is the most expensive way to call a function and should be avoided in time critical code. A well motivated use of apply is in conjunction with generic interfaces where several modules provide the same set of functions.
![]() |
The syntax |
The use of apply/3
for just calling different functions
within the same module (i.e apply(mymodule,Func,Args)
) is
not recommended. The use of Funs can often be a more efficient
way to accomplish calls which are variable in runtime.
When writing recursive functions it is preferable to make them tail-recursive so that they can execute in a constant memory space.
DO
list_length(List) -> list_length(List, 0). list_length([], AccLen) -> AccLen; % Base case list_length([_|Tail], AccLen) -> list_length(Tail, AccLen + 1). % Tail-recursive
DO NOT
list_length([]) -> 0. % Base case list_length([_ | Tail]) -> list_length(Tail) + 1. % Not tail-recursive
Do not evaluate the same expression in each recursive step, rather pass the result around as a parameter. For example imagine that you have the function in_range/3 below and want to write a function in_range/2 that takes a list of integers and atom as argument. The atom specifies a key to the named table range_table, so you can lookup the max and min values for a particular type of range.
in_range(Value, Min, Max) -> (Value >= Min) and (Value =< Max).
DO
in_range(ValuList, Type) -> %% Will be evaluated only one time ... [{Min, Max}] = ets:lookup(range_table, Type), %% ... send result as parameter to recursive help-function lists_in_range(ValuList, Min, Max). lists_in_range([Value | Tail], Min, Max) -> case in_range(Value, Min, Max) of true -> lists_in_range(Tail, Min, Max); false -> false end; lists_in_range([], _, _) -> true.
DO NOT
in_range([Value | Tail], Type) -> %% Will be evaluated in each recursive step [{Min, Max}] = ets:lookup(range_table, Type), case in_range(Value, Min, Max) of true -> lists_in_range(Tail, Type); false -> false end; in_range([], _, _) -> true.