Erlang Central

Function Clause

Revision as of 19:52, 10 March 2012 by Grig (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

A function with the same name and the same number of parameters can be defined several times, where through pattern matching, the clause chosen depends on the parameters and arguments passed to it. Consider the following example:

factorial(1) -> 1;									
factorial(N) -> N * factorial(N-1).

if the argument in the function call is not 1, the second clause is automatically chosen, and the argument is bound to N. If the argument is 1, the first clause is chosen, and 1 is returned.

Technically speaking, formal parameters are also patterns - it's just that they never fail to match a value. As a "side effect" of the successful match, the formal parameter is bound to the value it is being matched against. Patterns such as formal parameters that never fail to match are said to be irrefutable, in contrast to refutable patterns that may fail to match. Consider the following function:

factorial(N) ->

In this function, the formal parameter is N. If you execute the function factorial with ANY value as parameter, N will match it and become bound. In this case the pattern N is irrefutable. However, we know that the factorial function can only take positive integers larger than 0 as input.

factorial(N) when is_integer(N), (N > 0) ->

In this case, N can only be bound if it is integer and larger than 0. Now the pattern is refutable. Technically, we have placed two guards that prevents N from being bound:

  1. is_integer(N) and
  2. N > 0

We can also achieve refutability by including complex patterns in the function clause:

function({result,R} = P) ->							
 ... ;
function({response,R} = P) ->							
  ... ;
function({error,E} = P) ->
  ... .

In the example above, our function will match one of 3 clauses depending on the structure of the single parameter P.

{result,R} = P 

This means that IF the input parameter is a tuple of arity 2 and the first element is the atom result, then bind the variable R to the second element and the variable P to the entire tuple:

(rvg@wyemac2)32> Value = {result,"My result"}.
{result,"My result"}
(rvg@wyemac2)33> ({result,R} = P) = Value.
{result,"My result"}
(rvg@wyemac2)34> R.
"My result"
(rvg@wyemac2)35> P.
{result,"My result"}

In the same manner, Erlang will pick the correct clause in our function, generating an EXIT if none matched.