One: Function
1: In Erlang, two functions with the same name but different number of parameters are completely different functions.
2: Functions in other modules are called with fully qualified names:
-module(sort1).
-export([reverse_sort/1, sort/1]).
reverse_sort(L) ->
lists1:reverse(sort(L)).
sort(L) ->
lists:sort(L).
3: The clauses are separated by semicolons [;], and end with [.] at the end.
4: Each function consists of a set of clauses. The clauses are separated by semicolon ";". Each clause contains a clause header, an optional protection form and clause body. The header of a clause contains a function name and a set of comma-separated parameters. When a function call occurs, the headers of the clauses in the function definition will be matched in sequence. All assertions when evaluating the protection form will be evaluated. If all assertions are true, the protection is true, otherwise it will fail. The evaluation order of each assertion in the protection formula is uncertain.
If the protection formula is true, the body of the clause will be evaluated. If the protected version fails, try the next candidate clause. Once the header and protection of the clause are matched successfully, the system will specify this clause and evaluate its body. The combination of clause header pattern and protection form can uniquely determine a correct clause.
The complete set of protected assertions is as follows:
Protective | Conditions for establishment |
---|---|
atom(X) | X is an atomic formula |
constant(X) | X is not a list or tuple |
float(X) | X is a floating point number |
integer(X) | X is an integer |
list(X) | X is a list or [] |
number | X is an integer or floating point number |
pid(X) | X is a process identifier |
port(X) | X is a port |
reference(X) | X is a quote |
tuple(X) | X is a tuple |
binary(X) | X is a piece of binary data |
In addition, some combinations of BIF and arithmetic expressions can also be used as protective expressions. They are:
element/2, float/1, hd/1, length/1, round/1, self/0, ze/1
trunc/1, tl/1, abs/1, node/1, node/0, nodes/0
The term comparison operators that can appear in the protection formula are as follows:
Operators | describe | type |
---|---|---|
X > Y | X is greater than Y | coerce |
X < Y | X less than Y | coerce |
X =< Y | X less than or equal to Y | coerce |
X >= Y | X is greater than or equal to Y | coerce |
X == Y | X is equal to Y | coerce |
X /= Y | X is not equal to Y | coerce |
X =:= Y | X is equal to Y | exact |
X =/= Y | X is not equal to Y | exact |
The working mechanism of the comparison operator is as follows: first evaluate both sides of the operator (for example, when there are arithmetic expressions on both sides of the expression or include BIF protected functions); then compare.
For comparison, the partial order relationship is defined as follows:
number < atom < reference < port < pid < tuple < list
Tuples are sorted first by size and then by element. The comparison order of the list is first and then the tail.
If both parameters of the comparison operator are numeric types and the operator is coerce type, if one parameter is integer and the other is float, then integer will be converted to float and then compared.
Operators of exact type do not perform such conversions.
So 5.0 == 1 + 4 is true, while 5.0 =:= 4 + 1 is false.
Example of protection function clause:
foo(X, Y, Z) when integer(X), integer(Y), integer(Z), X == Y + Z ->
foo(X, Y, Z) when list(X), hd(X) == {Y, length(Z)} ->
foo(X, Y, Z) when {X, Y, size(Z)} == {a, 12, X} ->
foo(X) when list(X), hd(X) == c1, hd(tl(X)) == c2 ->
Note that no new variables can be introduced in the protection form.
2. Process control
case statement
The case expression allows selection among multiple options within the body of the clause, and the syntax is as follows:
case Expr of
Pattern1 [when Guard1] -> Seq1;
Pattern2 [when Guard2] -> Seq2;
...
PatternN [when GuardN] -> SeqN
end
First, evaluate Expr, and then, the value of Expr will be matched with the patterns Pattern1, Pattern2, and PatternN in turn until the match is successful. If a match is found and the (optional) protection formula holds, the corresponding call sequence will be evaluated. Note that the case protection form is the same as the function protection form. The value of the case primitive is the value of the selected sequence.
At least one pattern must be matched - otherwise a runtime error will be generated and an error handling mechanism in Chapter ?? will be raised.
For example, for example, I have a function allocate(Resource) for allocating a certain resource. Suppose this function returns only {yes, Address} or no. In this way, this function can be placed in a case structure:
...
case allocate(Resource) of
{yes,Address} when Address > 0, Address =< Max ->
Sequence 1 ... ;
no ->
Sequence 2 ...
end
...
In Sequence 1 ..., the variable Address has been bound to the return result of allocate/1.
In order to avoid matching errors, we often append a pattern that must match as the last branch of the case primitive:
case Fn of
...
_ ->
true
end
IF
The syntax of an if expression is as follows:
if
Guard1 ->
Sequence1 ;
Guard2 ->
Sequence2 ;
...
end
In this case, the protective Guan1,... will be evaluated in sequence. If a protection formula is true, the sequence associated with it is evaluated. The evaluation result of this sequence is the result of the if structure. If protection is the same as the function protection. Like case, if a protection method is not valid, an error will be raised. If needed, you can add a protective assertion true as a trash bin:
if
...
true ->
true
end
Arithmetic expressions
An arithmetic expression consists of the following operators:
Operators | describe | type | Operand type | Priority |
---|---|---|---|---|
+ X | + X | Monograph | mix | 1 |
- X | - X | Monograph | mix | 1 |
X * Y | X * Y | Binocular | mix | 2 |
X / Y | X / Y (floating point division) | Binocular | mix | 2 |
X div Y | X Divide Y | Binocular | Integer | 2 |
X rem Y | X divided by Y remainder | Binocular | Integer | 2 |
X band Y | X and Y | Binocular | Integer | 2 |
X + Y | X + Y | Binocular | mix | 3 |
X - Y | X - Y | Binocular | mix | 3 |
X bor Y | X and Y positions or | Binocular | Integer | 3 |
X bxor Y | X and Y bit arithmetics | Binocular | Integer | 3 |
X bsl N | X Arithmetic shift left N bit | Binocular | Integer | 3 |
X bsr N | X Right shift N bit | Binocular | Integer | 3 |
The monocular operator has one parameter, and the binocular operator has two parameters. Mix means that the parameters can be integer or float. The return value of the monocular operator is the same as its parameter type.
The binocular hybrid operator (i.e. * , - , + ) returns an object of type integer when the parameters are integer, and a float when the parameters contain at least one float. The floating point division operator/ always returns a float.
The parameters of the binocular integer operator (i.e. band , div , rem , bor , bxor , bsl , bsr ) must be integers, and their return value is also integers.
The order of evaluation depends on the operator's priority: first calculate the operator of priority 1, then the second priority 2, and so on. Expressions in brackets are evaluated first.
Operators with the same priority are evaluated from left to right.