Recursion and Pattern Matching
The following code contains the definitions of the function create_intervals
, which divides the total interval of numbers between 1 and n
into a number of smaller intervals that can be further treated by parallel processes.
create_intervals(ListLen, Delta) when ListLen =< Delta ->
create_intervals(ListLen, Delta) ->
create_intervals(Delta + 1, ListLen, Delta, [[1, Delta]]).
create_intervals(StartIndex, ListLen, Delta, L) when ... ->
create_intervals(StartIndex, ListLen, Delta, L) ->
A for loop could be a natural choice here, but Erlang substitutes iteration with recursion. Therefore, create_intervals calls itself and recursively builds a list of lists, with two atoms representing the extreme indexes of smaller intervals.
If you look at the same compute function, which divides a list of numbers into groups, calculates the single products for each group, and returns them in lists shorter than the initial one, you realize that applying it recursively at the end of the process results in a number that is the product of the numbers in the initial list. For this reason, the last line in the compute function is:
Coming back to the function create_interval, note that it has multiple definitions that differ for guard clauses as well as for different input patterns.
Erlang uses pattern matching intensively both in choosing the right function to call and in assigning variables. In fact, you can read the operator = not as "equal to" but as "match to," an assertion that two items are equal also with regard to their shape. It is a subtle distinction but an important concept to keep in mind when reading or writing Erlang code. For example, when you enter the following code:
A = 1.
The system tries to match variable A with 1. If the system uses A for the first time the match succeeds and binds the variable A to 1, from then on A will match only 1 and any other match/assignment will fail.
You can foresee the potential of pattern matching with this example:
L = [a, b, c, d].
[A | B] = L.
The notation | separates the head of a list (first item) from the tail (the remaining items). So, in this statement, pattern matching binds the variable A to atom a and B to the list [b, c, d].
Also, if you write:
[C, D | E] = L.
C will be bound to a, D to b, and E to the list [c,d].