Introduction to Erlang : Control Flow
- Introduction to Erlang post series
- Introduction to Erlang : Installing Erlang
- Introduction to Erlang : Typing
- Introduction to Erlang : Basic Types (1/2)
- Introduction to Erlang : Basic Types (2/2)
- Introduction to Erlang : Modules & Compilation
- Introduction to Erlang : Declaring Functions
- Introduction to Erlang : Control Flow
- Introduction to Erlang : Recursion (1/2)
- Introduciton to Erlang : Recursion (2/2)
- Introduction to Erlang : BIFs & Predefined Modules
- Introduction to Erlang : List & lists Module
- Introduction to Erlang : List Comprehension
- Introduction to Erlang : Concurrency (Processes)
- Introduction to Erlang : Message Passing
- Introduction to Erlang : Shared Memory Example
Control Flow
As we saw in the previous post, pattern matching with different function clauses can be used in order to control the execution flow in Erlang. Erlang also provides the if
, case
, and receive
control flow constructs that can be used in a function body. In this post I will only present the if
and case
statements since receive
is used for message passing and I will write a dedicated post about the subject. Both if
and case
are similar to the equivalent statements of other programming languages.
if statement
The format of an if
statement in Erlang is the following:
if Boolean_Expression1 -> If_body1; Boolean_Expression2 -> If_body2; ... true -> If_body_cath_all end |
So the different clauses, except the last one, are like else if
in other languages, while the last one (true ->
) is like the else
; it succeeds when all the previous clauses have failed.
Examples
month/1
month(M) -> if M == 1 -> jan; M == 2 -> feb; M == 3 -> mar; M == 4 -> apr; M == 5 -> may; M == 6 -> jun; M == 7 -> jul; M == 8 -> aug; M == 9 -> sep; M == 10 -> oct; M == 11 -> nov; M == 12 -> dec; true -> {error, not_valid_month_value} end. |
This is a different implementation of month/1
function that we saw in the previous post.
time/1
time("24:00") -> time("00:00"); time(Time = [H1, H2, $:, M1, M2]) when ((H1 >= $0) and (H1 =< $2)) and ((H2 >= $0) and (H2 =< $9)) and ((M1 >= $0) and (M1 =< $5)) and ((M2 >= $0) and (M2 =< $9)) and not((H1 == $2) and (H2 > $4)) and not(([H1, H2] == "24") and (not([M1, M2] == "00"))) -> HH = list_to_integer([H1, H2]), if HH == 12 -> Time ++ " PM"; HH > 12 -> integer_to_list(HH - 12) ++ [$:, M1, M2 | " PM"]; true -> Time ++ " AM" end; time(_) -> incorrect_time_format. |
This function can be used to convert the time from the 24h system to the AM/PM one. A much nicer implementation can be programmed, but I used this one because it illustrates several things:
- pattern matching of strings as lists
- pattern matching of characters (
$:
has the value 58; the ASCII code of “:”) - using guards
- using built-in (BIF) functions
- concatenating lists/strings
case statement
The format of a case
statement in Erlang is the following:
case Expression of Value1 [when Guard1] -> Case_body1; Value2 [when Guard2]-> Case_body2; _Other -> Case_body_catch_all end |
Notice that the last clause (_Other
) is like the default
clause in other programming languages. The Expression
should always return a value (if it is a function call) that will be used to perform the pattern matching.
Examples
month/1
month(M) -> case M of 1 -> jan; 2 -> feb; 3 -> mar; 4 -> apr; 5 -> may; 6 -> jun; 7 -> jul; 8 -> aug; 9 -> sep; 10 -> oct; 11 -> nov; 12 -> dec; _Other -> {error, not_valid_month_value} end. |
This month/1
implementation looks “better” than the previous ones.
palindrome/1
palindrome(List) when is_list(List) -> case lists:reverse(List) of List -> true; _ -> false end; palindrome(_) -> {error, arg_not_list}. |
This function checks if a list is a palindrome. Palindromes are the lists that remain the same if reversed. For example, [a], [a,a], [a, b, a]
are all palindromes.
Next
In the next post, I will introduce recursion; one of the most important characteristics of a functional language.
You should let month(M) crash if M is not in 1..12
month(M) ->
case M of
1 -> jan;
2 -> feb;
3 -> mar;
4 -> apr;
5 -> may;
6 -> jun;
7 -> jul;
8 -> aug;
9 -> sep;
10 -> oct;
11 -> nov;
12 -> dec
end
saying that month(foo) => unknown, for example, is nonsence.
Programs should crash as soon as possible if the inputs are incorrect.
/joe
You are right on this. Thanks 🙂
What I wanted to show is the “catch all” semantics of the
case
statement in Erlang.