Download as pdf or txt
Download as pdf or txt
You are on page 1of 254

Learn You Some Erlang for Great Good!

Erlang !

: Frederic Trottier-Hebert

v. 0.17.0

1.1

Erlang ! , ,
Erlang, .
, Haskell
! Miran Lipovaca. ,
.
, , , , Erlang.
,
.
, . ,
:
( web ,
, ). ,
LYAH. , -
Erlang , . ,
, Erlang .
, ,
.
Erlang , ( C/C++,
1

Java, Python, Ruby ..) (Haskell, Scala, Erlang, Clojure, OCaml. . . )


, Erlang,
.
1.2

Erlang?

, Erlang  . -
, i++; . .
, !
, 
:
y=2
x=y+3
x=2+3
x=5
:
x=5+1
x=x
= 5 = 6
. : , x 5, , ,
, x 6! .
:
x = add_two_to(3) = 5
= x = 5
,
,
. , add_two_to(3)
5, 3+2 5. , ,
, . , ? , :
x = today() = 2009/10/22
 
x = today() = 2009/10/23
2

x=x
= 2009/10/22 = 2009/10/23
, ! ! !
,
?
, ,
. Erlang : ( , ..), , .
, , Erlang  . . , Erlang ,  . ,
Erlang, , . :
 ; 
, ,
, .
- Erlang ,
. . ( ), ,
, , , .
- , ( ).
. , Erlang (),
, ,
.
, . Erlang . : Erlang
. - . Erlang,
3

Java, . ( ) (,
, , unit-),
Open Telecom Platform (OTP), -, mnesia
 -, ,
, Erlang.

, ,
,
.
,
Erlang: .
, , . ,
, ,
.
, Erlang
, , . . . .
1.3

- , ( ). Erlang , . , Erlang 
, .
, .
, Erlang, . , , Erlang
: , , 4

, . , . ,
, . . a -
, .
, !
,
, .
, , .
! ,
!  .
Erlang , ,
, .
, , .
: Erlang
, -, , . .
, ,
. Erlang  ,
,
. (, map-reduce),
, , .. , , .
Erlang. , .
IANO  , UNICT. Erlang
eurobot 2009 .  Wings 3D.
(
) , Erlang.

1.4


Erlang. Windows Erlang. ,
Windows . Erlang PATH,
.
Debian- Linux
# apt-get install erlang . Fedora ( yum),
, # yum install erlang . ,

Erlang. ,
. ,
.
. README, , Google ,
, .
FreeBSD . postmaster ,
postmaster lang/erlang .

cd /usr/ports/lang/erlang;make install clean .
, , ,
pkg_add -rv erlang .
OSX, Erlang
brew install erlang
Homebrew,
port install erlang , MacPorts.
: Erlang R13B+,
,
.
1.5

, . man , Linux.
, Erlang lists ( ):

6

$ erl -man lists .


Windows HTML. Erlang
.
, - ,
, .
.
,
. , : ( ) irc #erlang irc.freenode.net.
, trapexit .
. - .

2.1

Erlang .
, . Linux, $ erl . ,
:
E rl an g R13B01 ( e r t s - 5 . 7 . 2 ) [ s o u r c e ] [ smp : 2 : 2 ]
[ rq : 2 ] [ async - t h r e a d s : 0 ] [ h i p e ] [ k e r n e l - p o l l : f a l s e ]
E s h e l l V5 . 7 . 2

( a b o r t with ^G)

, Erlang!
Windows erl.exe , werl.exe , ( programs > Erlang ).
Werl Erlang, Windows.

(, , -,
cmd.exe Windows). , , erl - .
, .

2.2

Erlang
Emacs, 70- . Emacs, .
.
, -
^A (Ctrl+A), . ^E (Ctrl+E)
. ,
.
, . .
, , li tab,
lists: . tab , , lists:. Erlang
lists , .
, , . , , . :
! .
help(). , ( ( . ),
). , :
q()  quit - shorthand for init:stop()
( , ).
, ! ,
, , ^G . h, .
User s w i t c h command
- -> h
c [ nn ]
i [ nn ]
k [ nn ]
j
s [ shell ]
r [ node [ s h e l l ] ]
-

connect to job
i n t e r r u p t job
k i l l job
l i s t a l l jobs
start local shell
s t a r t remote s h e l l
9

q
? | h
- ->

- quit erlang
- t h i s message

i c , Erlang
. j
( , ). ,
i . k , . s
.
E s h e l l V5 . 7 . 2 ( a b o r t with ^G)
1> "OH NO THIS SHELL IS UNRESPONSIVE! ! ! * h i t s c t r l+G* "
User s w i t c h command
- -> k
- -> c
Unknown j o b
- -> s
- -> j
2* { s h e l l , s t a r t , [ ] }
- -> c 2
E s h e l l V5 . 7 . 2 ( a b o r t with ^G)
1> "YESS ! "
, , , , .
, ,
Erlang, . ( -).

10

3
(-)
Erlang ( , C C++). . .
, , ,
Erlang.

3.1

Erlang , ( , ..), . ,
(,
).
.
, Erlang Prolog  .
Erlang ,
, - - !
1> 2 + 1 5 .
17
2> 49 * 1 0 0 .
4900
3> 1892 - 1 4 7 2 .
420
4> 5 / 2 .
11

2.5
5> 5 d i v 2 .
2
6> 5 rem 2 .
1
, Erlang ,
: . , -,
, Erlang. , 
div ,
rem (remainder, ).
, , .
7> ( 5 0 * 1 0 0 ) - 4 9 9 9 .
1
8> - ( 5 0 * 100 - 4 9 9 9 ) .
-1
9> -50 * ( 1 0 0 - 4 9 9 9 ) .
244950
10, #
( 2. . . 36):
10> 2#101010.
42
11> 8#0677.
447
12> 16#AE.
174
! Erlang , - . , ! !
3.2

, . 12

. ,
, .
7 ( ,
):
1> One .
* 1 : v a r i a b l e ' One '
2> One = 1 .
1
3> Un = Uno = One =
1
4> Two = One + One .
2
5> Two = 2 .
2
6> Two = Two + 1 .
** e x c e p t i o n e r r o r :
7> two = 2 .
** e x c e p t i o n e r r o r :

i s unbound
1.

no match o f r i g h t hand s i d e v a l u e 3
no match o f r i g h t hand s i d e v a l u e 2

, : , , , ,
. Erlang- , . = . = ( )
, . , :
8> 47 = 45 + 2 .
47
9> 47 = 45 + 3 .
** e x c e p t i o n e r r o r : no match o f r i g h t hand s i d e v a l u e
48
:  ( ), Erlang
, ,
. , .
= (pattern matching), 13

, Erlang
. ,
, ,
.
, 1-7 ,
.
7 , two
. ('_'),
, , - , , .
,
:
10> _ = 14+3.
17
11> _.
* 1 : v a r i a b l e '_ ' i s unbound
,
. , , .
.
: , f(Variable). . , f(). .
, .
.
, Erlang : ,
. . . , X
.
3.3

,
.  . ,
14

. cat cat
. , ,
; cat. C .
,
, :
1> atom .
atom
2> atoms_rule .
atoms_rule
3> atoms_rule@erlang .
atoms_rule@erlang
4> ' Atoms can be c h e a t e d ! ' .
' Atoms can be c h e a t e d ! '
5> atom = ' atom ' .
atom

, (_) @, (').
5 , , ,
, .
, . , , . , , , : BLUE -> 1, BROWN -> 2,
GREEN -> 3, OTHER -> 4 . . .
'blue', 'brown', 'green'
'other'.
: , , , .
, -
. 4.
, ,
. .
. ,
.
15


. .
, (4 / 32- , 8 / 64-
). , ,
- ,
 1048577.
.
, , , - , .
, .
:
, :
, , ..
bnot bor bsl bsr bxor case catch
: after and andalso band begin
cond div end fun if let not of or orelse query receive rem try when xor
3.4


, ,
. Erlang, ,
. :
1> t r u e and f a l s e .
false
2> f a l s e o r t r u e .
true
3> t r u e xor f a l s e .
true
4> not f a l s e .
true
5> not ( t r u e and t r u e ) .
false
16

: and or , -

. ,
, andalso orelse .
, , ,
:
6> 5 =:=
true
7> 1 =:=
false
8> 1 =/=
true
9> 5 =:=
false
10> 5 ==
true
11> 5 /=
false

5.
0.
0.
5.0.
5.0.
5.0.

-,
== != , Erlang =:=
=/= . ( 9 11)
: Erlang
,
. ,
, == /= .
, ,
.
: < ( ), > (
), >= ( ) =< ( ). , -, -
. =< .
12> 1 < 2 .
true
13> 1 < 1 .
false
14> 1 >= 1 .
true
17

15> 1 =< 1 .
true
, 5 + llama 5 == true ?
, !
12> 5 + l l a m a .
** e x c e p t i o n e r r o r : bad argument i n an a r i t h m e t i c
expression
i n o p e r a t o r +/2
c a l l e d as 5 + llama
, ? Erlang , ! . , ,
+ !
, Erlang - :
13> 5 =:= t r u e .
false
, ? Erlang
, . ,
Erlang ,
, , , .
.
,
:
14> 0 == f a l s e .
false
15> 1 < f a l s e .
true

- , , ,
. 14 true, 15 false !
false 0, true  ! Erlang.
. , . .
Erlang true false. true false , 18

, , ,
false true  false true, .
:
:
number < atom < reference < fun < port < pid < tuple < list < bit string
,
. , !
Joe Armstrong, Erlang: ,
, .
3.5

 .
, .
Erlang : {Element1, Element2,. . . , ElementN} .
(x, y), .
:
1> X = 1 0 , Y = 4 .
4
2> Po in t = {X,Y} .
{ 10 ,4 }
.
, X Y,
. , , X ?
. , ,
Erlang , . ! ,
f() , .
3> Po in t = { 4 , 5 } .
{ 4 ,5 }
4> {X,Y} = Po in t .
{ 4 ,5 }
5> X.
4
6> {X,_} = P oi nt .
{ 4 ,5 }
19


, X ! ? X Y ,
.
{X, Y} = . = {X, Y} {4, 5}. Erlang ,
.
{4, 5} = {4, 5} , , , !
(pattern matching).
, _. :
, . _ (wildcard) .
( ) .
7> {_,_} = { 4 , 5 } .
{ 4 ,5 }
8> {_,_} = { 4 , 5 , 6 } .
** e x c e p t i o n e r r o r : no match o f r i g h t hand s i d e v a l u e {
4 ,5 ,6 }
. , :
9> Temperature = 2 3 . 2 1 3 .
23.213
. . . -,
, ?
10> P r e c i s e T e m p e r a t u r e = { c e l s i u s , 2 3 . 2 1 3 } .
{ celsius ,23.213 }
11> { k e l v i n , T} = P r e c i s e T e m p e r a t u r e .
** e x c e p t i o n e r r o r : no match o f r i g h t hand s i d e v a l u e {
celsius ,23.213 }
, , !
. =
20

{kelvin, T} {celsius, 23.213}. , T , Erlang celsius kelvin. , . ,


, , .
. ,
,  .
, :
12> { p o i n t , {X,Y} } .
{ point , { 4 ,5 }}
, ?
3.6

 .
, , , Erlang.
! , , , 
. :
[Element1, Element2,. . . ,ElementN] ,
:
1> [ 1 , 2 , 3 , { numbers , [ 4 , 5 , 6 ] } , 5 . 3 4 , atom ] .
[ 1 , 2 , 3 , { numbers , [ 4 , 5 , 6 ] } , 5 . 3 4 , atom ]
, ?
2> [ 9 7 , 9 8 , 99 ] .
" abc "
-! Erlang, :
!  ,
! ? :
3> [ 9 7 , 9 8 , 9 9 , 4 , 5 , 6 ] .
[ 97 ,98 ,99 ,4 ,5 ,6 ]
4> [ 233 ] .
" e "

21

Erlang ,
! Erlang !
, - .  . C .

, , Erlang , , ,
. , Erlang . ( )
, . , Erlang
. Unicode-,
.
,
.
.
, Erlang , , ,
, Perl Python.
++ .
, :
5> [ 1 , 2 , 3 ] ++
[ 1 ,2 ,3 ,4 ,5 ]
6> [ 1 , 2 , 3 , 4 , 5 ]
[ 4 ,5 ]
7> [ 2 , 4 , 2 ] - [2]
8> [ 2 , 4 , 2 ] - []

[ 4 ,5 ] .
- - [ 1 ,2 ,3 ] .
[ 2 ,4 ] .
[ 2 ,4 ,2 ] .

, ++  . ,
++
, :
9> [ 1 , 2 , 3 ] - - [ 1 , 2 ] - - [ 3 ] .
[3]
10> [ 1 , 2 , 3 ] - - [ 1 , 2 ] - - [ 2 ] .
22

[ 2 ,3 ]
. ( ), ( ). :
11> hd ( [ 1 , 2 , 3 , 4 ] ) .
1
12> t l ( [ 1 , 2 , 3 , 4 ] ) .
[ 2 ,3 ,4 ]

: (),

Erlang.
, Erlang ( 80-
Prolog). , Erlang,
.
length(List) , ( ,
, ) ,
.

. , ,
. - ,
,
 : [Head|Tail] .
:
13> L i s t = [ 2 , 3 , 4 ] .
[ 2 ,3 ,4 ]
14> NewList = [ 1 | L i s t ] .
[ 1 ,2 ,3 ,4 ]

, .
,
({X, Y}), ,
().
15> [ Head | T a i l ] = NewList .
[ 1 ,2 ,3 ,4 ]
16> Head .
1
23

17> T a i l .
[ 2 ,3 ,4 ]
18> [ NewHead | NewTail ] = T a i l .
[ 2 ,3 ,4 ]
19> NewHead .
2
| cons- ().
cons- :
20> [ 1 | [ ] ] .
[1]
21> [ 2 | [ 1 | [ ] ] ] .
[ 2 ,1 ]
22> [ 3 | [ 2 | [ 1 | [ ] ] ] ] .
[ 3 ,2 ,1 ]
, : [Term1| [Term2 | [. . . | [TermN]]]]. . . . , , , ,
, . :
, .

Erlang
, .
24

,
(: ):
[a,
[a,
[a,
[a,
[a
[a

b, c , d]
b, c , d | [ ] ]
b | [c , d] ]
b | [ c | [d] ] ]
| [b | [ c | [d] ] ] ]
| [b | [ c | [d | [ ] ] ] ] ]

,
.

: [1 | 2] .
[Head|Tail] ,
Erlang ( length() ) . . .
: [2] ,
. [1|[2]] !
, -
, .
3.7

. , , .
; - , , .
, . , , , .
, !
: {x R : x =
2
x }. ,
, . {0, 1}.
25

{x : x > 0} . 0.
Erlang
. {2n : n in L} ,
L  [1, 2, 3, 4]. Erlang :
1> [ 2*N | | N <- [ 1 , 2 , 3 , 4 ] ] .
[ 2 ,4 ,6 ,8 ]
Erlang, , :
({}) ([]), (:) (||), in (< ).
, .
, , [1, 2, 3, 4] N (
). ,
= , , .

, , . ,
- :
2> [X | | X <- [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 ] , X rem 2 =:= 0 ] .
[ 2 ,4 ,6 ,8 ,10 ]
X rem 2 =:= 0 . ,
- .. , . , ,
, $3 $10, (,
7%), .
3> RestaurantMenu = [ { s t e a k , 5 . 9 9 } , { beer , 3 . 9 9 } , {
p o u t i n e , 3 . 5 0 } , { k i t t e n , 2 0 . 9 9 } , { water , 0 . 0 0 } ] .
[ { steak , 5 . 9 9 } ,
{ beer , 3 . 9 9 } ,
{ poutine , 3 . 5 } ,
{ kitten ,20.99 } ,
{ water , 0 . 0 } ]
4> [ { Item , P r i c e * 1 . 0 7 } | | { Item , P r i c e } <RestaurantMenu , P r i c e >= 3 , P r i c e =< 10 ] .
26

[ { s t e a k , 6 . 4 0 9 3 0 0 0 0 0 0 0 0 0 0 1 } , { beer , 4 . 2 6 9 3 } , { p o u t i n e , 3 . 7 4 5
}]
, , . ,
Erlang : NewList = [Expression || Pattern

< List, Condition1, Condition2, ... ConditionN] . Pattern < List


. !
5> [X+Y | | X <- [ 1 , 2 ] , Y <- [ 2 , 3 ] ] .
[ 3 ,4 ,4 ,5 ]
: 1 + 2 , 1 + 3 , 2 + 2 , 2 + 3 .
: NewList =
[Expression || GeneratorExp1, GeneratorExp2, ..., GeneratorExpN,
Condition1, Condition2, ... ConditionM] . , - , :
6> Weather = [ { t o r o n t o , r a i n } , { montreal , s t o r m s } , {
london , f o g } ,
6>
{ p a r i s , sun } , { boston , f o g } , { vancouver ,
snow} ] .
[ { toronto , rain } ,
{ montreal , s t o r m s } ,
{ london , f o g } ,
{ p a r i s , sun } ,
{ boston , f o g } ,
{ vancouver , snow} ]
7> FoggyPlaces = [X | | {X, f o g } <- Weather ] .
[ london , b o s t o n ]
Weather {X, fog},
, = .
, . Erlang ,
.

27

3.8

, , , , / ..
. Erlang .
( ) .
. ,
, ,
, .

, << >>,
. 
( ,
). , 24- .
-
Photoshop CSS, #RRGGBB
. #F09A29. Erlang
:
1> C o l o r = 16#F09A29 .
15768105
2> P i x e l = <<C o l o r :24 > >.
<<240,154,41>>
- :
#F09A29 24- ( 8 , 8
8 ) Pixel.
.
, ,
. Erlang,
<<240,151,41>>!
,
:
3> P i x e l s = < <213 ,45 ,13 2 ,64 , 76 ,32 ,76 ,0 ,0 ,23 4 ,32 , 15 > >.
28

< <213 ,45 ,132 ,64 ,76 ,32 ,76 ,0 ,0 ,234 ,32 ,15 > >
4> <<Pix1 , Pix2 , Pix3 , Pix4>> = P i x e l s .
** e x c e p t i o n e r r o r : no match o f r i g h t hand s i d e v a l u e
< < 2 13 , 4 5 , 1 3 2 , 6 4 , 7 6 , 3 2 , 7 6 ,
0 ,0 ,234 ,32 ,15 > >
5> <<Pix1 : 2 4 , Pix2 : 2 4 , Pix3 : 2 4 , Pix4 :24>> = P i x e l s .
< <213 ,45 ,132 ,64 ,76 ,32 ,76 ,0 ,0 ,234 ,32 ,15 > >
3- , 4- RGB . 4- 4 .
,
4 , 12! Erlang,
24 . Var:24 .

:
6> <<R: 8 , G: 8 , B:8>> = <<Pix1 :24 > >.
<<213,45,132>>
7> R.
213
, . ? ?
! ! Erlang , :
8> <<R: 8 , Rest / b inary >> = P i x e l s .
< <213 ,45 ,132 ,64 ,76 ,32 ,76 ,0 ,0 ,234 ,32 ,15 > >
9> R.
213
, ? Erlang . :
Value
Value:Size
Value/TypeSpecierList
Value:Size/TypeSpecierList
Size , TypeSpecierList
:

29

: integer | oat | binary | bytes | bitstring | bits | utf8


| utf16 | utf32
. ,
'bytes' 'binary', 'bits' 'bitstring'.
, Erlang 'integer'.

: signed | unsigned
,  integer.
'unsigned'.

: big | little | native


, integer, utf16, utf32
oat. , .
, BMP
4- . 72
, little-endian 72,0,0,0 ,
big-endian 0,0,0,72 .
'72', '1207959552', ,
. 'native',
, .
'big'.

unit:Integer
. 1..256.
1 integer, oat, 8
. utf8, utf16 utf32
.
, , 8.

.
TypeSpecierList , '-'.
:
10> <<X1/ unsigned >> =

<<"O">>

<<-44>>.

30

11> X1 .
212
12> <<X2/ s i g n e d >> = <<-44>>.

<<"O">>
13> X2 .
-44
14> <<X2/ i n t e g e r - s i g n e d - l i t t l e >> = <<-44>>.

<<"O">>
15> X2 .
-44
16> <<N: 8 / u n i t :1>> = <<72>>.
<<"H">>
17> N.
72
18> <<N/ i n t e g e r >> = <<72>>.
<<"H">>
19> <<Y: 4 / l i t t l e - u n i t :8>> = < <72 ,0 ,0 ,0 > >.
<<72,0,0,0>>
20> Y.
72
, , . ,
, ,
.
Erlang ( , '', '', ' ' '').
bsl (Bit Shift Left ( )), bsr (Bit Shift Right ( )), band , bor , bxor ,
bnot .
2#00100 = 2#00010 b s l 1 .
2#00001 = 2#00010 b s r 1 .
2#10101 = 2#10001 bor 2#00101.

.
, TCP :
<<S o u r c e P o r t : 1 6 , D e s t i n a t i o n P o r t : 1 6 ,
AckNumber : 3 2 ,
D a t a O f f s e t : 4 , _Reserved : 4 , F l a g s : 8 , WindowSize : 1 6 ,
CheckSum : 1 6 , U r g e n t P o i n t e r : 1 6 ,
31

Payload / bi nary >> = SomeBinary .


:
, ,
..

Erlang, ++, .
- Erlang,
. , ,
,
. Erlang .
, Erlang ,
: , (
) .. Erlang
, ,
(soft real time).

: . , . ,
. .
, (1 ),
C.
<<this is a bit string! >> .
.
, , , .

32

: ,
.
{<<temperature >>,50}
,
.
, 4 8 ,
. ,
,
Erlang .
: .
(, ..) , .
3.9

,
: . Erlang .
Erlang, ,
, .
R13B ( ), , :
1> [ X | | <<X>> <= < <1 ,2 ,3 ,4 ,5 > > , X rem 2 == 0 ] .
[ 2 ,4 ]
 < <= , (<<>>) ([]). ,
, . ,
RGB . ,
, .
, :
2> P i x e l s = < <213 ,45 ,13 2 ,64 , 76 ,32 ,76 ,0 ,0 ,23 4 ,32 , 15 > >.
< <213 ,45 ,132 ,64 ,76 ,32 ,76 ,0 ,0 ,234 ,32 ,15 > >
3> RGB = [ {R, G, B} | | <<R: 8 ,G: 8 ,B:8>> <= P i x e l s ] .
[ { 213 ,45 ,132 } , { 64 ,76 ,32 } , { 76 ,0 ,0 } , { 234 ,32 ,15 } ]

33

< <=
. , , . , :
4> << <<R: 8 , G: 8 , B:8>> | | {R,G, B} <- RGB >>.
< <213 ,45 ,132 ,64 ,76 ,32 ,76 ,0 ,0 ,234 ,32 ,15 > >
. ,
:
5> << <<Bin>> | | Bin <- [ <<3,7,5,4,7>> ] >>.
** e x c e p t i o n e r r o r : bad argument
6> << <<Bin / b inar y >> | | Bin <- [ <<3,7,5,4,7>> ] >>.
<<3,7,5,4,7>>
,
:
7> << <<(X+1)/ i n t e g e r >> | | <<X>> <= <<3,7,5,4,7>> >>.
<<4,8,6,5,8>>

: , . .
, , .

34

4.1


.
. Erlang, . , , .
,
Erlang. , -
!
.  , .
Erlang . , . hd
tl , ,
erlang , ,
. erlang ,
Erlang . , ,
: Module:Function(Arguments) .
:
1> e r l a n g : e l e m e n t ( 2 , {a , b , c } ) .
b
35

2> e l e m e n t ( 2 , {a , b , c } ) .
b
3> l i s t s : s e q ( 1 , 4 ) .
[ 1 ,2 ,3 ,4 ]
4> s e q ( 1 , 4 ) .
** e x c e p t i o n e r r o r : u n d e f i n e d s h e l l command s e q /2
seq list , element . undened shell
command , (, f() ). erlang
, .
, ,
, .
lists , - (
), io . , ,
erlang , ,
, ,
.. , ,
. ,
erlang , .
4.2


: . , : , , , . ,
,
, , .
Erlang .
. , .
-Name(Attribute). .
36

, :

-module(Name).

, Name 3.3 . .
M:F(A) , M , F A .
!
. ,
, useless.erl :
- module ( u s e l e s s ) .
. , . , .
:

-export([Function1/Arity, Function2/Arity,. . . ,FunctionN/Arity]).

, .
. , , . , , ,
, .
add(X, Y) add(X, Y, Z)
add/2 add/3 .

. , .
, ,
.
add, . -export
:
- e x p o r t ( [ add /2 ] ) .
:
add (A, B) ->
A + B.

Name(Args) > Body. ,


Name , Body ,
37

Erlang, . .
, Erlang return.
return ! , .
( ,
Hello world! !),
-export .
%% Shows g r e e t i n g s .
%% i o : format /1 i s t h e s t a n d a r d f u n c t i o n used t o output t e x t .
h e l l o ( ) ->
i o : format ( " H e l l o , world ! ~n" ) .

,
% (,
%% , ).
hello/0
. io:format/1 ,
(
).
, add/2 ,
hello/0 :
greet_and_add_two (X) ->
hello () ,
add (X, 2 ) .

greet_and_add_two/1
.
hello/0 add/2 , .

io:format/1 add/2
, ,
: -import(io, [format/1]). .
format(Hello, World!n). . -import :
- import ( Module , [ Function1 / Arity , . . . , FunctionN / A r i t y ] ) .

38

. Erlang -import , , .
, io:format/2
io_lib:format/2 . , ,
, . .
, lists,
.
useless :
- module ( u s e l e s s ) .
- e x p o r t ( [ add / 2 , h e l l o / 0 , greet_and_add_two /1 ] ) .
add (A, B) ->
A + B.
%% Shows g r e e t i n g s .
%% i o : format /1 i s t h e s t a n d a r d f u n c t i o n used t o output t e x t .
h e l l o ( ) ->
i o : format ( " H e l l o , world ! ~n" ) .
greet_and_add_two (X) ->
hello () ,
add (X, 2 ) .

useless. useless.erl .
, -module , '.erl',
Erlang.
, -,
, . Erlang
#dene C, ,
, .
,
. ,
.
-dene(MACRO, some_value).
?MACRO .
-dene(sub(X, Y), X - Y). ?sub(23, 47) . 39

23 - 47 . - ,
.
4.3

Erlang ,
-.
: $ erlc ags le.erl ,
compile:le(FileName) , c() ..
.
Erlang :
1> cd ( "/ path / t o / where / you / saved / the - module / " ) .
" Path Name t o t h e d i r e c t o r y you a r e i n "
ok

,
, .
cd/1 Erlang. . Windows ( / ).
,
, :
2> c ( u s e l e s s ) .
{ok , u s e l e s s }

, , , ,
. , , useless.erl
 useless.beam . .
:
3> u s e l e s s : add ( 7 , 2 ) .
9
4> u s e l e s s : h e l l o ( ) .
H e l l o , world !
ok
5> u s e l e s s : greet_and_add_two ( - 3 ) .
H e l l o , world !
-1
6> u s e l e s s : not_a_real_function ( ) .
** e x c e p t i o n e r r o r : u n d e f i n e d f u n c t i o n u s e l e s s :
not_a_real_function /0

40

: add/2 ,
hello/0 Hello, world!, greet_and_add_two/1
! , , : hello/0 ok? Erlang - ,
. io:format/1 ok, ,
.
6 ,
- . , .
: '.beam', ,
Bogdan/Bj
orn's Erlang Abstract Machine ( ). Erlang,
, .
JAM (Joe's Abstract Machine, Prolog WAM, BEAM, Erlang C,
 . , , .
, . Erlang. :

-debug_info

, Erlang, , .

-{outdir,Dir}

Erlang beam
. , .

-export_all

-export .
, . ,
.

41

{d,Macro} {d,Macro,Value}

, . Macro . -, ,

. Value true, .
useless , :
7> c o m p i l e : f i l e ( u s e l e s s , [ debug_info , e x p o r t _ a l l ] ) .
{ok , u s e l e s s }
8> c ( u s e l e s s , [ debug_info , e x p o r t _ a l l ] ) .
{ok , u s e l e s s }

. 7 8,
:
- c o m p i l e ( [ debug_info , e x p o r t _ a l l ] ) .

,
, . ,
, ,
, !
: .

. , , ( 20%). hipe . :
hipe:c(Module,OptionsList). c(Module,[{hipe,o3}]). , .beam , , , .
4.4

, , ,
.
42

. ,  ,
. ,
? . (
) module_info/0 . useless :
9> u s e l e s s : module_info ( ) .
[ { e x p o r t s , [ {add , 2 } ,
{ hello ,0 } ,
{greet_and_add_two , 1 } ,
{ module_info , 0 } ,
{ module_info , 1 } ] } ,
{ imports , [ ] } ,
{ a t t r i b u t e s , [ { vsn , [ 174839656007867314473085021121413256129 ] } ]
},
{ compile , [ { o p t i o n s , [ ] } ,
{ version , " 4 . 6 . 2 "} ,
{ time , { 2 0 0 9 , 9 , 9 , 2 2 , 1 5 , 5 0 } } ,
{ s o u r c e , " /home/ f e r d / l e a r n - you - some - e r l a n g / u s e l e s s . e r l " } ] } ]
10> u s e l e s s : module_info ( a t t r i b u t e s ) .
[ { vsn , [ 174839656007867314473085021121413256129 ] } ]


module_info/1 ,
.
, ( ), ( , ), . -author(An Erlang Champ). ,
, vsn . ,
, :
, , -
. , ,
, .
: vsn , , . ( , ), , . , vsn :
-vsn(VersionNumber) .
43

,

: ! A
B, A. .
,
- - ,
.
(
), .
, .
, .
Erlang?

44

5

5.1

, ,
. ,
,
. . , ,
.
- :
f u n c t i o n g r e e t ( Gender , Name)
i f Gender == male then
p r i n t ( " H e l l o , Mr . %s ! " , Name)
e l s e i f Gender == f e m a l e then
p r i n t ( " H e l l o , Mrs . %s ! " , Name)
else
p r i n t ( " H e l l o , %s ! " , Name)
end

, Erlang . Erlang
:
g r e e t ( male , Name) ->
i o : format ( " H e l l o , Mr . ~s ! " , [ Name ] ) ;
g r e e t ( f emal e , Name) ->
i o : format ( " H e l l o , Mrs . ~s ! " , [ Name ] ) ;
g r e e t (_, Name) ->
i o : format ( " H e l l o , ~s ! " , [ Name ] ) .

45

, Erlang , , . ,
,
: , , . ,
! :
f u n c t i o n ( Args )
i f X then
Expression
e l s e i f Y then
Expression
else
Expression

:
f u n c t i o n (X) ->
Expression ;
f u n c t i o n (Y) ->
Expression ;
f u n c t i o n (_) ->
Expression .

,
. function .
( ; ) . , .
(workow),
, .
, ,
!

46

: io:format

, . ( ~ ).
, ~n . .
. , io:format(~s!~n,[Hello]).
~n , ~s ,
. ,
Hello!n .
~p . Erlang,
( ).
io:format , /.
:
io:format(~s~n,[<<Hello >>]) ,
io:format~p~n, [<<Hello >>]) ,
io:format(~~~n) , io:format(~f~n, [4.0]) , io:format(~30f~n, [4.0]) .
.
printf . ,
/, .

. , , ,
, . ! functions .
, :
- module ( f u n c t i o n s ) .
- c o m p i l e ( e x p o r t _ a l l ) . %% r e p l a c e with - e x p o r t ( ) l a t e r , f o r God ' s
sake !

head/1 ,
erlang:hd/1 :
.
cons ( | ):
head ( [H|_] ) -> H.

functions:head([1,2,3,4]). (
), '1'.
, , :
47

s e c o n d ( [ _,X|_] ) -> X.

Erlang . !
1> c ( f u n c t i o n s ) .
{ok , f u n c t i o n s }
2> f u n c t i o n s : head ( [ 1 , 2 , 3 , 4 ] ) .
1
3> f u n c t i o n s : s e c o n d ( [ 1 , 2 , 3 , 4 ] ) .
2

,
. , , ,
. .
,
3 .
, , . same/2 ,
, :
same (X,X) ->
true ;
same (_,_) ->
false .

. ,
,

:

, Erlang

: ! ,
, (

). 48

.
, Erlang . , . , ,
-. ,
, . , . ,
3.2 .
. same(a,a) ,
X
a . Erlang ,
X .
a , , ,
.
true .
, ,
, ( , !), false. ,
!
, .
: , , , :
v a l i d _ t i m e ( { Date = {Y,M,D} , Time = {H, Min , S} } ) ->
i o : format ( "The Date t u p l e (~p ) s a y s today i s : ~p/~p/~p , ~ n" , [
Date , Y,M,D] ) ,
i o : format ( "The time t u p l e (~p ) i n d i c a t e s : ~p : ~ p : ~ p . ~ n" , [ Time
, H, Min , S ] ) ;
v a l i d _ t i m e (_) ->
i o : format ( " Stop f e e d i n g me wrong data ! ~n" ) .

= , ( {Y,M,D} ),
(Date ). :
4> c ( f u n c t i o n s ) .
{ok , f u n c t i o n s }
5> f u n c t i o n s : v a l i d _ t i m e ( { { 2 0 1 1 , 0 9 , 0 6 } , { 0 9 , 0 4 , 4 3 } } ) .
The Date t u p l e ( { 2 0 1 1 , 9 , 6 } ) s a y s today i s : 2 0 1 1 / 9 / 6 ,
The time t u p l e ( { 9 , 4 , 4 3 } ) i n d i c a t e s : 9 : 4 : 4 3 .
ok

49

6> f u n c t i o n s : v a l i d _ t i m e ( { { 2 0 1 1 , 0 9 , 0 6 } , { 0 9 , 0 4 } } ) .
Stop f e e d i n g me wrong data !
ok

, ! , .
, {{A,B,C}, {D,E,F}} .
: , ,
, , | ,
N , ( _ ),
.. ,
(guards).
5.2

! !

 , , . , , ,
, , .
: , ?
, ? ,
, ? ,
. , :
old_enough ( 0 ) -> f a l s e ;
old_enough ( 1 ) -> f a l s e ;
old_enough ( 2 ) -> f a l s e ;
...
old_enough ( 1 4 ) -> f a l s e ;
old_enough ( 1 5 ) -> f a l s e ;
old_enough (_) -> t r u e .

. , ,
.
,
guards ,
:
old_enough (X) when X >= 16 -> t r u e ;

50

old_enough (_) -> f a l s e .

! , .
: , true . false ,
, . , 104 .
16 104 . ?
:
r i g h t _ a g e (X) when X >= 1 6 , X =< 104 ->
true ;
r i g h t _ a g e (_) ->
false .

( , ) andalso ,
( ; ) orelse ( ?? ).
, .
:
wrong_age (X) when X < 1 6 ; X > 104 ->
true ;
wrong_age (_) ->
false .

. , ( !).
( ; ) orelse : , , ,

.
,
, ( A*B/C >= 0 ) , is_integer/1 , is_atom/1 , ..
( ).
,
- . Erlang
, ( , ,
51

Haskell) :
-, , . , , , . .
. Erlang
(, , !)
,
,
.
: , ;
andalso orelse . , . ,
. ,
X >= N; N >= 0 ,
, . X >= N orelse N >= 0 ,
, .
, ( - ) andalso
orelse . ,
(A orelse B) andalso C , (A; B), C  .
.
5.3

If?!

If -
, .
. if - Erlang if - . ,
, , .
Erlang, if .
 .
if ,
:
- module ( what_the_if ) .
- e x p o r t ( [ heh_fine /0 ] ) .
heh_fine ( ) ->

52

i f 1 =:= 1 ->
works
end ,
i f 1 =:= 2 ; 1 =:= 1 ->
works
end ,
i f 1 =:= 2 , 1 =:= 1 ->
fails
end .

what_the_if.erl , :
1> c ( what_the_if ) .
. / what_the_if . e r l : 1 2 : Warning : no c l a u s e w i l l e v e r
match
. / what_the_if . e r l : 1 2 : Warning : t h e guard f o r t h i s
c l a u s e e v a l u a t e s to ' f a l s e '
{ok , what_the_if }
2> what_the_if : heh_fine ( ) .
** e x c e p t i o n e r r o r : no t r u e branch found when
e v a l u a t i n g an i f e x p r e s s i o n
i n f u n c t i o n what_the_if : heh_fine /0
! , if 12 ( 1 =:= 2, 1 =:= 1 )
, false . , Erlang -
, if - . , Erlang ,

, :
. ,
.
'else'. Erlang 'true' ( ,
VM no true branch found)
oh_god (N) ->

53

i f N =:= 2 -> might_succeed ;


t r u e -> always_does %% t h i s i s Er lang ' s i f ' s ' e l s e ! '
end .

(
.
, ):
3> c ( what_the_if ) .
. / what_the_if . e r l : 1 2 : Warning : no c l a u s e w i l l e v e r match
. / what_the_if . e r l : 1 2 : Warning : t h e guard f o r t h i s c l a u s e
e v a l u a t e s to ' f a l s e '
{ok , what_the_if }
4> what_the_if : oh_god ( 2 ) .
might_succeed
5> what_the_if : oh_god ( 3 ) .
always_does

, if -. ,
- : Talk
if , . , true , , Erlang
null- ( nil lisp, NULL
C, None Python ..):
%% note , t h i s one would be b e t t e r a s a p a t t e r n match i n f u n c t i o n
heads !
%% I 'm d o i n g i t t h i s way f o r t h e s a k e o f t h e example .
help_me ( Animal ) ->
Talk = i f Animal == c a t -> "meow" ;
Animal == b e e f -> "mooo" ;
Animal == dog -> " bark " ;
Animal == t r e e -> " bark " ;
t r u e -> " f g d a d f g n a "
end ,
{ Animal , " s a y s " ++ Talk ++ " ! " } .

:
6> c ( what_the_if ) .
. / what_the_if . e r l : 1 2 : Warning : no c l a u s e w i l l e v e r match
. / what_the_if . e r l : 1 2 : Warning : t h e guard f o r t h i s c l a u s e
e v a l u a t e s to ' f a l s e '
{ok , what_the_if }
7> what_the_if : help_me ( dog ) .
{dog , " s a y s bark ! " }
8> what_the_if : help_me ( " i t h u r t s ! " ) .

54

{" i t hurts ! " , " says fgdadfgna ! "}

Erlang, , ,  'true' 'else' ? , 'else' . Richard


O'Keefe Erlang .
, :
, 'else' , , 'else' .
, '; true ->'
Erlang 'else', ,
. :
i f X > Y ->
; true
i f X > Y ->
; X < Y
; true
end

a ()
-> b ( )
a ()
-> b ( )
-> c ( )

i f X > Y -> a ( )
; X =< Y -> b ( )
end
i f X > Y -> a ( )
; X < Y -> b ( )
; X == Y -> C( )
end

, , ,
.
'else' 'true': if - ,
, , .
, ( 6
( ).
Erlang. case !

55

: ,
what_the_if.erl , if , -

if . Erlang
,
.
5.4

. . .

, if , case . . . of
.
, ,
!
, .
(append) (sets) ( ),
. ,
, , , :
i n s e r t (X, [ ] ) ->
[X] ;
i n s e r t (X, S e t ) ->
c a s e l i s t s : member (X, S e t ) o f
t r u e -> S e t ;
f a l s e -> [X| S e t ]
end .

() X,
, X. , lists:member/2 , ,
true, false, . ,
X, . , X
.
, .
( ):
beach ( Temperature ) ->
c a s e Temperature o f
{ c e l s i u s , N} when N >= 2 0 , N =< 45 ->
' favorable ' ;
{ k e l v i n , N} when N >= 2 9 3 , N =< 318 ->
' s c i e n t i f i c a l l y favorable ' ;
{ f a h r e n h e i t , N} when N >= 6 8 , N =< 113 ->

56

_ ->
end .

' f a v o r a b l e i n t h e US ' ;
' a v o i d beach '

?
: , .
, ,
, .
, case. . . of ,
.
:
b e a c h f ( { c e l s i u s , N} ) when N >= 2 0 , N =< 45 ->
' favorable ' ;
...
b e a c h f (_) ->
' a v o i d beach ' .

: if , case . . . of
?
5.5

?,  .
case . . . of
. , ,
.
57

, :
function(A,B) -> . . . end. , A B, case
:
c a s e {A, B} o f
P a t t e r n Guards -> . . .
end .

,
.
. , insert/2 ,
, ,
, true false .
: if , case
, if ? if :
, , , .
, . .
Erlang.
, ,
. Ward Cunningham:
, , , .

58

6
( )
6.1

, , 3,
4 5, .
, . {X,Y}
{atom, 123} ,
{A string, binary stu!} , {2.0, [strings, and, atoms]}
.
,
. 
Erlang.
. , ,
llama + 5 3.


. ,
59

, ,
.
, . , Erlang
, . (availability)
(99.9999999%), Ericsson
AXD 301 ATM. Erlang-  1 . 
, , Erlang, . ,
99.9999999% , . , Erlang ,
. , , . , ,
.
, , Erlang
, ,
, . Erlang 
. , .
:
. , Erlang,
, Erlang
.
, Erlang  .
.
Erlang , , , 6 = 5 + 1 . , :
1> 6 + "1 " .
** e x c e p t i o n e r r o r : bad argument i n an a r i t h m e t i c e x p r e s s i o n
i n o p e r a t o r +/2
c a l l e d as 6 + "1"

60

, ,
. , , .
Erlang .
6.2

, Erlang . ,

Erlang. <>_to_<> erlang . :
1> e r l a n g : l i s t _ t o _ i n t e g e r ( " 54 " ) .
54
2> e r l a n g : i n t e g e r _ t o _ l i s t ( 5 4 ) .
" 54 "
3> e r l a n g : l i s t _ t o _ i n t e g e r ( " 5 4 . 3 2 " ) .
** e x c e p t i o n e r r o r : bad argument
i n f u n c t i o n l i s t _ t o _ i n t e g e r /1
c a l l e d as l i s t _ t o _ i n t e g e r ( " 54.32 " )
4> e r l a n g : l i s t _ t o _ f l o a t ( " 5 4 . 3 2 " ) .
54.32
5> e r l a n g : atom_to_list ( t r u e ) .
" true "
6> e r l a n g : l i s t _ t o _ b i t s t r i n g ( " h i t h e r e " ) .
<<" h i t h e r e ">>
7> e r l a n g : b i t s t r i n g _ t o _ l i s t (<<" h i t h e r e ">>) .
" hi there "

.
. <>_to_<>,
! :
atom_to_binary/2, atom_to_list/1, binary_to_atom/2
binary_to_existing_atom/2, binary_to_list/1,
bitstring_to_list/1, binary_to_term/1, oat_to_list/1,
fun_to_list/1, integer_to_list/1, integer_to_list/2,
iolist_to_binary/1, iolist_to_atom/1, list_to_atom/1,
list_to_binary/1, list_to_bitstring/1,
list_to_existing_atom/1, list_to_oat/1, list_to_integer/2,
61

list_to_pid/1, list_to_tuple/1, pid_to_list/1,


port_to_list/1, ref_to_list/1, term_to_binary/1,
term_to_binary/2 tuple_to_list/1.
. , ,
. , .
6.3

Erlang :
,  ,
.. : head/1 ,
, , ( [H|_] ).

, , .
,
, ..
. , ,
, ?
, , ,
. , :
is_atom /1
i s _ b i t s t r i n g /1
i s _ f l o a t /1
i s _ i n t e g e r /1
i s _ p i d /1
i s _ r e c o r d /3

i s _ b i n a r y /1
i s _ b o o l e a n /1
i s _ f u n c t i o n /1
i s _ l i s t /1
i s _ p o r t /1
i s _ r e f e r e n c e /1

62

i s _ b u i l t i n /3
i s _ f u n c t i o n /2
is_number /1
i s _ r e c o r d /2
i s _ t u p l e /1

, ,
, . , , : , (- type_of(X) -> Type ). . Erlang
: , , , . . , , 9, , .
.
: ,
. ,
. :
abs(Number), bit_size(Bitstring), byte_size(Bitstring),
element(N, Tuple), oat(Term), hd(List), length(List),
node(), node(Pid|Ref|Port), round(Number), self(),
size(Tuple|Bitstring), tl(List), trunc(Number), tuple_size(Tuple).
node/1 self/0
Erlang /. ,
.
, Erlang
,
. , {node, Value, Left, Right} , Left Right
, , . :
{ person , {name , <<" Fred T-H">>} ,
{ q u a l i t i e s , [ " handsome " , " smart " , " h o n e s t " , " o b j e c t i v e " ] } ,
{ faults , [ " liar " ] } ,
{ s k i l l s , [ " programming " , " b a s s g u i t a r " , " underwater
breakdancing " ] }} .

,
. ,
, ,
.

63

: R13B04
binary_to_term/2 , ,

binary_to_term/1 , ,
. [safe] ,
, 8
, ,
.
6.4

,
. ,
. ,
Erlang, , , .
, Erlang.
,
, .. : ,
.

Erlang.
1997 Simon Marlow, Glasgow Haskell Compiler Philip Wadler,
Haskell ,
( , ). Joe Armstrong
:

64

, ) Erlang
, ) )
,
Erlang, : ?. : .
Phil Wadler Simon Marlow ,
[20].
. ,
, .
, .
Erlang. .
Erlang.
HiPE ( Erlang)
Dialyzer, ,
. (type inference).
, ,
(success typings)  , Hindley-Milner (soft-typing).
: , ,
, , ,
.

and ,
'true', , 'false'.
Haskell and :: bool -> bool -> bool .
and Erlang,
:
and ( f a l s e , _) -> f a l s e ;
and (_, f a l s e ) -> f a l s e ;
and ( t r u e , t r u e ) -> t r u e .

,
and(_,_) -> bool() , _ . : false
42 , 'false'. _ ,
,
65

'false'. ML (
), .
Erlang. , , .
.
.
Erlang 8 (EEP8).
Erlang,
TypEr Dialyzer. .
, $ typer help $ dialyzer help
( Windows typer.exe help dialyzer help , ).
TypEr . TypEr
FIFO
:
%% F i l e : f i f o . e r l
%% - - - - - - - - - - - - - - s p e c new ( ) -> { ' f i f o ' , [ ] , [ ] } .
- s p e c push ( { ' f i f o ' ,_,_} ,_) -> { ' f i f o ' ,
nonempty_maybe_improper_list ( ) ,_} .
- s p e c pop ( { ' f i f o ' ,_, maybe_improper_list ( ) } ) -> {_, { ' f i f o ' ,_,_} } .
- s p e c empty ( { ' f i f o ' ,_,_} ) -> b o o l ( ) .

, , . Improper ,
lists:reverse/1 , - -
, .
push/2 pop/2 -
, . , .
,
-spec push({fo,list(),list()},_) -> {fo,nonempty_list(),list()}.
, improper push/2 . Dialyzer- ( ),
The call fo:push(fo,[1|2],[],3) breaks the

contract '<Type denition here>>>.
Dialyzer ,
, , ,
( ,
,
66

). Dialyzer-
. hd()
-spec([A]) -> A. ,
Erlang .

Dialyzer TypEr ,
. Erlang  , ,
, . , ,
( ),
, ( , . . . )
,
- TypEr Dialyzer ( , ).
.
, , Scala, Haskell OCaml.

.

.
, .

67

R13B04, Dialyzer
. . .
, , , ( ) ,
EEP8.

68

7.1

, !

,
-
, ,
, .
: ?
,
, for while .
- , .
, , . , 3.2 ! . ,
,
. n
1 2 3 . . . n n n 1 n 2 . . . 1 .
, 3 3! = 3 2 1 = 6 . 4 4! = 4 3 2 1 = 24 .
:
(
1
if x = 0
n! =
n((n 1)!) if x < 0
, n 0, 69

1. 0 n
n - 1 , , ,
1.

4! = 4 3!
4! = 4 3 2!
4! = 4 3 2 1!
4! = 4 3 2 1 1
Erlang?
. : n! , 1 n((n-1)!) , if -.
( n! ), (
if -) (1 n((n-1)!) ). n! fac(N) ,
, :
- module ( r e c u r s i v e ) .
- e x p o r t ( [ f a c /1 ] ) .
f a c (N) when N == 0 -> 1 ;
f a c (N) when N > 0 -> N* f a c (N- 1 ) .

!
.
, :
f a c ( 0 ) -> 1 ;
f a c (N) when N > 0 -> N* f a c (N- 1 ) .

,
, Erlang . !
, . ( ),
.
 , n 0.
, , ,
.
7.2

. , , .
70

, :
;
, ;
, .
,
.
, ? ,
, , 0. ,
[] = 0 . 1: [_] = 1 . , ,
:
l e n ( [ ] ) -> 0 ;
l e n ( [_] ) -> 1 .

! ,
0 1 ! . ,
, .
:
,
0 1. 3.6 ,
[1 | [2| . . . [n| []]]] . ,
[H|T] ,
[X|[]] ,
[X|[Y|[]]] . ,
. ,
. ,
1,
:
l e n ( [ ] ) -> 0 ;
l e n ( [_| T ] ) -> 1 + l e n (T) .

,
. -

71

. , , [1,2,3,4] :

len([1, 2, 3, 4]) = len([1|[2, 3, 4])


= 1 + len([2|[3, 4, ]])
= 1 + 1 + len([3|[4]])
= 1 + 1 + 1 + len([4|[]])
= 1 + 1 + 1 + 1 + len([])
=1+1+1+1+0
=1+1+1+1
=1+1+2
=1+3
=4
. Erlang!
7.3

, ,
,
. , , .
. , , .
.

(
) ( ). , .
: - ,
. 1 + len(Rest) , len(Rest) .
len(Rest) , , . , ,
72

.
.
, .
. .
. , ,
:
t a i l _ f a c (N) -> t a i l _ f a c (N, 1 ) .
t a i l _ f a c ( 0 , Acc ) -> Acc ;
t a i l _ f a c (N, Acc ) when N > 0 -> t a i l _ f a c (N- 1 ,N*Acc ) .

tail_fac/1 tail_fac/2 .
, Erlang ( c ,  ),
. tail_fac/1
tail_fac/2 , .
, tail_fac/2 , tail_fac/1 .
:

tail_f ac(4) = tail_f ac(4, 1)


tail_f ac(4, 1) = tail_f ac(4 1, 4 1)
tail_f ac(3, 4) = tail_f ac(3 1, 3 4)
tail_f ac(2, 12) = tail_f ac(2 1, 2 12)
tail_f ac(1, 24) = tail_f ac(1 1, 1 24)
tail_f ac(0, 24) = 24
? . ,
, . 4
, 1000000 (
, 4!
, 1000000!).
73

, , , ,
len/1 .
,
. , , , +1 :
l e n ( [ ] ) -> 0 ;
l e n ( [_| T ] ) -> 1 + l e n (T) .

:
t a i l _ l e n (L) -> t a i l _ l e n (L , 0 ) .
t a i l _ l e n ( [ ] , Acc ) -> Acc ;
t a i l _ l e n ( [_| T ] , Acc ) -> t a i l _ l e n (T, Acc+1) .

.
7.4


, . ,  ,
Erlang ( ), .
,
,
!
,  duplicate/2 . ,  .
, , . , . ,
duplicate/2 , - 0 . , .
, . ,

74

, -n :
d u p l i c a t e ( 0 ,_) ->
[];
d u p l i c a t e (N, Term ) when N > 0 ->
[ Term | d u p l i c a t e (N- 1 , Term ) ] .

,
, .
:
t a i l _ d u p l i c a t e (N, Term ) ->
t a i l _ d u p l i c a t e (N, Term , [ ] ) .
t a i l _ d u p l i c a t e ( 0 ,_, L i s t ) ->
List ;
t a i l _ d u p l i c a t e (N, Term , L i s t ) when N > 0 ->
t a i l _ d u p l i c a t e (N- 1 , Term , [ Term | L i s t ] ) .

! , while.
tail_duplicate/2 ,
while. while
Erlang,
:
f u n c t i o n (N, Term ) ->
w h i l e N > 0 ->
L i s t = [ Term | L i s t ] ,
N = N- 1
end ,
List .

,
, Erlang. . , , , ,
while.
,
. reverse/1 , -.
, .
. , ,
75

duplicate/2 .
[H|T] , H
:
r e v e r s e ( [ ] ) -> [ ] ;
r e v e r s e ( [H| T ] ) -> r e v e r s e (T)++[H] .

:
, ,
!
:

reverse([1, 2, 3, 4]) = [4] + +[3] + +[2] + +[1]


= [4, 3] + +[2] + +[1]
= [4, 3, 2] + +[1]
= [4, 3, 2, 1]
. .
. :
t a i l _ r e v e r s e (L) -> t a i l _ r e v e r s e (L , [ ] ) .
t a i l _ r e v e r s e ( [ ] , Acc ) -> Acc ;
t a i l _ r e v e r s e ( [H|T ] , Acc ) -> t a i l _ r e v e r s e (T, [H| Acc ] ) .

, :

tail_reverse([1, 2, 3, 4]) = tail_reverse([2, 3, 4], [1])


= tail_reverse([3, 4, ], [2, 1])
= tail_reverse([4], [3, 2, 1])
= tail_reverse([], [4, 3, 2, 1])
= [4, 3, 2, 1]
,
. , !
 sublist/2 .
L N, N . , sublist([1,2,3,4,5,6],3) [1,2,3].
76

 0 . ,
: sublist/2 .
, ! , recursive:sublist([1],2). , [1] .
,
, ,
:
s u b l i s t (_, 0 ) -> [ ] ;
s u b l i s t ( [ ] ,_) -> [ ] ;
s u b l i s t ( [H| T ] ,N) when N > 0 -> [H| s u b l i s t (T, N- 1 ) ] .

, , , :
t a i l _ s u b l i s t (L , N) -> t a i l _ s u b l i s t (L , N, [ ] ) .
t a i l _ s u b l i s t (_, 0 , S u b L i s t ) -> S u b L i s t ;
t a i l _ s u b l i s t ( [ ] , _, S u b L i s t ) -> S u b L i s t ;
t a i l _ s u b l i s t ( [H| T ] , N, S u b L i s t ) when N > 0 ->
t a i l _ s u b l i s t (T, N- 1 , [H| S u b L i s t ] ) .

. !
, , -. ,
sublist([1,2,3,4,5,6],3) [1,2,3], [3,2,1].
.
tail_sublist/2 ,
:
t a i l _ s u b l i s t (L , N) -> r e v e r s e ( t a i l _ s u b l i s t (L , N, [ ] ) ) .

. ,  , (
). , - ,
, .
, .

77

: reverse/1
lists:reverse/1 .
, Erlang
. ( , C),
, , .
, .
, zip-.
. zip/2 :
1> r e c u r s i v e : z i p ( [ a , b , c ] , [ 1 , 2 , 3 ] ) .
[ {a , 1 } , {b , 2 } , { c , 3 } ]

, ,
:
z i p ( [ ] , [ ] ) -> [ ] ;
z i p ( [X| Xs ] , [Y| Ys ] ) -> [ {X,Y} | z i p ( Xs , Ys ) ] .

, ,
, ,
. :
l e n i e n t _ z i p ( [ ] ,_) -> [ ] ;
l e n i e n t _ z i p (_, [ ] ) -> [ ] ;
l e n i e n t _ z i p ( [X| Xs ] , [Y| Ys ] ) -> [ {X,Y} | l e n i e n t _ z i p ( Xs , Ys ) ] .

, , , .
zip/2
lenient_zip/2 , , . ,
,
.
, ,
recursive.erl, tail_zip/2 tail_lenient_zip/3 .

78

: ,

,
( , ), .
.
, .
, ,
Erlang . . , a() -> b(). b() -> c(). c() -> a().
, ,
.

.
7.5

, !

( ) , .
,
 . , , ,
.
, , ,
,

. . , , ,
. ,
. ,
.
:
79

, ,
. :
q u i c k s o r t ( [ ] ) -> [ ] ;
q u i c k s o r t ( [ P i v o t | Rest ] ) ->
{ S m a l l e r , L a r g e r } = p a r t i t i o n ( Pivot , Rest , [ ] , [ ] ) ,
q u i c k s o r t ( S m a l l e r ) ++ [ P i v o t ] ++ q u i c k s o r t ( L a r g e r ) .

: ; , ;
, . .
:
p a r t i t i o n (_, [ ] , S m a l l e r , L a r g e r ) -> { S m a l l e r , L a r g e r } ;
p a r t i t i o n ( Pivot , [H| T ] , S m a l l e r , L a r g e r ) ->
i f H =< P i v o t -> p a r t i t i o n ( Pivot , T, [H| S m a l l e r ] , L a r g e r ) ;
H > P i v o t -> p a r t i t i o n ( Pivot , T, S m a l l e r , [H| L a r g e r ] )
end .

.
Erlang, , , , , , .
, ,
partition/4 :
l c _ q u i c k s o r t ( [ ] ) -> [ ] ;
l c _ q u i c k s o r t ( [ P i v o t | Rest ] ) ->
l c _ q u i c k s o r t ( [ S m a l l e r | | S m a l l e r <- Rest , S m a l l e r =< P i v o t ] )
++ [ P i v o t ] ++
l c _ q u i c k s o r t ( [ L a r g e r | | L a r g e r <- Rest , L a r g e r > P i v o t ] ) .

, ,
, , .
.
,
lists:sort/1 . .

80

,
. ! -, , , . : ,
.
,
.
, . , ,
( bestest_qsort/1 ) recursive/erl.
, , , - . , !
7.6

, , , , Erlang,
, .

,
, , , . , ,
.
, .
.
 , ,
,
.
,
, . !  , , , ,
81

, .
( ),
, , ,
.
 .
{node, {Key, Value, Smaller, Larger}}
( !), Smaller Larger
, ( {node, nil} .
.
. empty/0  . 
,
:
- module ( t r e e ) .
- e x p o r t ( [ empty / 0 , i n s e r t / 3 , lookup /2 ] ) .
empty ( ) -> { node , ' n i l ' } .

, , , , ,
, . . -
 , .
, , ,
, , . ,
 .
, , ,
. /, .
, .
, .
,
,
, , . , , , .
: , ? :
, . 82

. , ,
:
i n s e r t ( Key , Val , { node , ' n i l ' } ) ->
{ node , {Key , Val , { node , ' n i l ' } , { node , ' n i l ' } } } ;
i n s e r t (NewKey , NewVal , { node , {Key , Val , S m a l l e r , L a r g e r } } ) when
NewKey < Key ->
{ node , {Key , Val , i n s e r t (NewKey , NewVal , S m a l l e r ) , L a r g e r } } ;
i n s e r t (NewKey , NewVal , { node , {Key , Val , S m a l l e r , L a r g e r } } ) when
NewKey > Key ->
{ node , {Key , Val , S m a l l e r , i n s e r t (NewKey , NewVal , L a r g e r ) } } ;
i n s e r t ( Key , Val , { node , {Key , _, S m a l l e r , L a r g e r } } ) ->
{ node , {Key , Val , S m a l l e r , L a r g e r } } .

, . , . , ,
,
, .
,
lookup/2 , . , ,
: , ,
, , .
:  ( ),
 . , , , ,
'undened'. ,
{ok, Value} . Value,
'undened', , .
.
:
lookup (_, { node , ' n i l ' } ) ->
undefined ;
lookup ( Key , { node , {Key , Val , _, _} } ) ->
{ok , Val } ;
lookup ( Key , { node , {NodeKey , _, S m a l l e r , _} } ) when Key < NodeKey
->
lookup ( Key , S m a l l e r ) ;
lookup ( Key , { node , {_, _, _, L a r g e r } } ) ->
lookup ( Key , L a r g e r ) .

83

, .  . :
1> T1 = t r e e : i n s e r t ( "Jim Woodland" , " jim . woodland@gmail . com" ,
t r e e : empty ( ) ) .
{ node , { "Jim Woodland" , " jim . woodland@gmail . com" ,
{ node , n i l } ,
{ node , n i l } } }
2> T2 = t r e e : i n s e r t ( "Mark Anderson " , " i . am . a@hotmail . com" , T1) .
{ node , { "Jim Woodland" , " jim . woodland@gmail . com" ,
{ node , n i l } ,
{ node , { "Mark Anderson " , " i . am . a@hotmail . com" ,
{ node , n i l } ,
{ node , n i l } } } } }
3> A d d r e s s e s = t r e e : i n s e r t ( " Anita Bath " , " abath@someuni . edu " ,
t r e e : i n s e r t ( " Kevin Robert " , " myfairy@yahoo . com" , t r e e : i n s e r t (
" Wilson Longbrow " , " l o n g w i l @ g m a i l . com" , T2) ) ) .
{ node , { "Jim Woodland" , " jim . woodland@gmail . com" ,
{ node , { " Anita Bath" , " abath@someuni . edu " ,
{ node , n i l } ,
{ node , n i l } } } ,
{ node , { "Mark Anderson " , " i . am . a@hotmail . com" ,
{ node , { " Kevin Robert " , " myfairy@yahoo . com" ,
{ node , n i l } ,
{ node , n i l } } } ,
{ node , { " Wilson Longbrow " , " l o n g w i l @ g m a i l . com" ,
{ node , n i l } ,
{ node , n i l } } } } } } }

:
4> t r e e : lookup ( " Anita Bath" , A d d r e s s e s ) .
{ok , " abath@someuni . edu "}
5> t r e e : lookup ( " J a c q u e s Requin " , A d d r e s s e s ) .
undefined

,
!

84

: : -

,
. /  gb_trees
( otp_src_R<version>B<revision>/lib/stdlib/src/gb_trees.erl ).
,
.
7.7

, , , .
( while for) ,
( , , , )
( , ,  ).
.
,
7 .
, ,
 .
, ,
,
(- ).
,
. .

, 

 , . ,
, , . ,
. ?
 . , . ,
. .
85

 , , .
.
 , . !
 . , ,
, ,
.
 , . ,
,
, , , .
 , , .
 .
. ,
,
. ,
, ,
, .
, ,
. ( , ),
, .
  ,
.
 , . . . . . . Erlang. . .
 , . - - , Erlang while
for. ,
C!
 -!
! , , , .
. , . 86

. . . .

87

8

8.1


. ,
, - ,
. ,
, .  ,
Erlang.
, , -. -, , ,
. ,
, , .  ,
,
, !
, , :
- module ( hhfuns ) .
- compile ( export_all ) .
one ( ) -> 1 .

88

two ( ) -> 2 .
add (X,Y) -> X( ) + Y( ) .

Erlang, :
1> c ( hhfuns ) .
{ok , hhfuns }
2> hhfuns : add ( one , two ) .
** e x c e p t i o n e r r o r : bad f u n c t i o n one
i n f u n c t i o n hhfuns : add /2
3> hhfuns : add ( 1 , 2 ) .
** e x c e p t i o n e r r o r : bad f u n c t i o n 1
i n f u n c t i o n hhfuns : add /2
4> hhfuns : add ( fun hhfuns : one / 0 , fun hhfuns : two / 0 ) .
3

? ,
( , ?). 2 one two add/2 ,
( X() + Y() ). ,
, , .
3. 1 2 ,
!
,
, . fun Module:Function/Arity . VM,
.
, ?
.
hhfuns ,
:
i n c r e m e n t ( [ ] ) -> [ ] ;
i n c r e m e n t ( [H| T ] ) -> [H+1| i n c r e m e n t (T) ] .
decrement ( [ ] ) -> [ ] ;
decrement ( [H| T ] ) -> [ H- 1 | decrement (T) ] .

?
: , ( + - ) .
89

, . ,
.
( map/2 ),
:
map(_, [ ] ) -> [ ] ;
map(F , [H| T ] ) -> [ F(H) | map(F , T) ] .
i n c r (X) -> X + 1 .
d e c r (X) -> X - 1 .

:
1> c ( hhfuns ) .
{ok , hhfuns }
2> L = [ 1 , 2 , 3 , 4 , 5 ] .
[ 1 ,2 ,3 ,4 ,5 ]
3> hhfuns : i n c r e m e n t (L) .
[ 2 ,3 ,4 ,5 ,6 ]
4> hhfuns : decrement (L) .
[ 0 ,1 ,2 ,3 ,4 ]
5> hhfuns : map( fun hhfuns : i n c r / 1 , L) .
[ 2 ,3 ,4 ,5 ,6 ]
6> hhfuns : map( fun hhfuns : d e c r / 1 , L) .
[ 0 ,1 ,2 ,3 ,4 ]

, ,
! , , map/2
. ,
, map/2 , , ,
.. , .
, . . .
8.2

, funs, ,
. ,
, ( ?
!) :
fun ( Args1 ) ->
E x p r e s s i o n 1 , Exp2 , . . . , ExpN ;

90

end

( Args2 ) ->
E x p r e s s i o n 1 , Exp2 , . . . , ExpN ;
( Args3 ) ->
E x p r e s s i o n 1 , Exp2 , . . . , ExpN

:
7> Fn = fun ( ) -> a end .
#Fun<e r l _ e v a l .20.67289768 >
8> Fn ( ) .
a
9> hhfuns : map( fun (X) -> X + 1 end , L) .
[ 2 ,3 ,4 ,5 ,6 ]
10> hhfuns : map( fun (X) -> X - 1 end , L) .
[ 0 ,1 ,2 ,3 ,4 ]

- , , , :
.
, , , , ,
.
 ,
:
11> PrepareAlarm = fun (Room) ->
11>
i o : format ( "Alarm s e t i n ~s . ~ n" , [ Room ] ) ,
11>
fun ( ) -> i o : format ( "Alarm t r i p p e d i n ~s !
C a l l Batman ! ~n" , [ Room ] ) end
11>
end .
#Fun<e r l _ e v a l .20.67289768 >
12> AlarmReady = PrepareAlarm ( " bathroom " ) .
Alarm s e t i n bathroom .
#Fun<e r l _ e v a l .6.13229925 >
13> AlarmReady ( ) .
Alarm t r i p p e d i n bathroom ! C a l l Batman !
ok

, ! ? -, , PrepareAlarm.
: PrepareAlarm(bathroom) .
io:format/2 ,
Alarm set. (
), AlarmReady. , Room (PrepareAlarm ).
91

(closures).
, ().
,
. base(A) -> B = A + 1. , A
B base/1 .
,
base/1 A B,
, .
   , , ;
:
b a s e (A) ->
B = A + 1,
F = fun ( ) -> A * B end ,
F() .

B base/1 , F . , F base/1 . , ,
, :
b a s e (A) ->
B = A + 1,
F = fun ( ) -> C = A * B end ,
F() ,
C.

, B A + 1 ,
F . C F. base/1
C, . ,
, . .
,
, :
a ( ) ->
S e c r e t = " pony " ,
fun ( ) -> S e c r e t end .

92

b (F) ->
" a / 0 ' s password i s "++F ( ) .

:
14> c ( hhfuns ) .
{ok , hhfuns }
15> hhfuns : b ( hhfuns : a ( ) ) .
" a / 0 ' s password i s pony "

a/0 ? a/0 .
a/0 , b/1 , .
,
, ( ,
).
, ,
 :
16> math : pow ( 5 , 2 ) .
25.0
17> Base = 2 .
2
18> PowerOfTwo = fun (X) -> math : pow ( Base ,X) end .
#Fun<e r l _ e v a l .6.13229925 >
17> hhfuns : map( PowerOfTwo , [ 1 , 2 , 3 , 4 ] ) .
[ 2.0 ,4.0 ,8.0 ,16.0 ]

math:pow/2 , Base , Base


PowerOfTwo.
, :
b a s e ( ) ->
A = 1,
( fun ( ) -> A = 2 end ) ( ) .

, .
base/0 , = 2 c 93

A ( 1).
. , , :
b a s e ( ) ->
A = 1,
( fun (A) -> A = 2 end ) ( 2 ) .

. (shadowing) ( Warning: variable 'A' shadowed in 'fun' ).


 , , ,
.
( ),
, .
, ,
,
.
8.3

(maps), ,
(folds)

,
map/2 .
,
,
- . :
map(_, [ ] ) -> [ ] ;
map(F , [H| T ] ) -> [ F(H) | map(F , T) ] .

, , ,
. :
%% o n l y keep even numbers

94

even (L) -> l i s t s : r e v e r s e ( even (L , [ ] ) ) .


even ( [ ] , Acc ) -> Acc ;
even ( [H| T ] , Acc ) when H rem 2 == 0 ->
even (T, [H| Acc ] ) ;
even ( [_| T ] , Acc ) ->
even (T, Acc ) .
%% o n l y keep men o l d e r than 60
old_men (L) -> l i s t s : r e v e r s e ( old_men (L , [ ] ) ) .
old_men ( [ ] , Acc ) -> Acc ;
old_men ( [ Person = { male , Age} | P eo pl e ] , Acc ) when Age > 60 ->
old_men ( People , [ Person | Acc ] ) ;
old_men ( [_| Pe op l e ] , Acc ) ->
old_men ( People , Acc ) .

. {, }
60 .
, . , ,
( ), .

:
f i l t e r ( Pred , L) -> l i s t s : r e v e r s e ( f i l t e r ( Pred , L , [ ] ) ) .
f i l t e r (_, [ ] , Acc ) -> Acc ;
f i l t e r ( Pred , [H| T ] , Acc ) ->
c a s e Pred (H) o f
t r u e -> f i l t e r ( Pred , T, [H| Acc ] ) ;
f a l s e -> f i l t e r ( Pred , T, Acc )
end .

-,
. hhfuns
:
1> c ( hhfuns ) .
{ok , hhfuns }
2> Numbers = l i s t s : s e q ( 1 , 1 0 ) .
[ 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ]
3> hhfuns : f i l t e r ( fun (X) -> X rem 2 == 0 end , Numbers ) .
[ 2 ,4 ,6 ,8 ,10 ]
4> P eo pl e = [ { male , 4 5 } , { fe male , 6 7 } , { male , 6 6 } , { f ema le , 1 2 } , {unkown
, 1 7 4 } , { male , 7 4 } ] .

95

[ { male , 4 5 } , { fema le , 6 7 } , { male , 6 6 } , { fem ale , 1 2 } , {unkown , 1 7 4 } , { male


,74 } ]
5> hhfuns : f i l t e r ( fun ( { Gender , Age} ) -> Gender == male a n d a l s o Age
> 60 end , P eo p le ) .
[ { male , 6 6 } , { male , 7 4 } ]

, , lter/2 , ,
. .
:
, ,
, .
, . (fold) :
%% f i n d t h e maximum o f a l i s t
max( [H| T ] ) -> max2 (T, H) .
max2 ( [ ] , Max) -> Max ;
max2 ( [H| T ] , Max) when H > Max -> max2 (T, H) ;
max2 ( [_| T ] , Max) -> max2 (T, Max) .
%% f i n d t h e minimum o f a l i s t
min ( [H| T ] ) -> min2 (T,H) .
min2 ( [ ] , Min ) -> Min ;
min2 ( [H| T ] , Min ) when H < Min -> min2 (T,H) ;
min2 ( [_| T ] , Min ) -> min2 (T, Min ) .
%% sum o f a l l t h e e l e m e n t s o f a l i s t
sum (L) -> sum (L , 0 ) .
sum ( [ ] , Sum) -> Sum ;
sum ( [H| T ] , Sum) -> sum (T, H+Sum) .

, , . ,
. , , .
. ,
, . ,
, sum.
96


, , , , .
sum/2 0, , 0, X = X + 0
.
X = X * 1 , 1. min/1
max/1
. ,
0, .
. ,
, .
, :
f o l d (_, S t a r t , [ ] ) -> S t a r t ;
f o l d (F , S t a r t , [H| T ] ) -> f o l d (F , F(H, S t a r t ) , T) .

:
6> c ( hhfuns ) .
{ok , hhfuns }
7> [H| T ] = [ 1 , 7 , 3 , 5 , 9 , 0 , 2 , 3 ] .
[ 1 ,7 ,3 ,5 ,9 ,0 ,2 ,3 ]
8> hhfuns : f o l d ( fun (A, B) when A > B -> A; (_, B) -> B end , H, T) .
9
9> hhfuns : f o l d ( fun (A, B) when A < B -> A; (_, B) -> B end , H, T) .
0
10> hhfuns : f o l d ( fun (A, B) -> A + B end , 0 , l i s t s : s e q ( 1 , 6 ) ) .
21

,
, .
,
( ), . .
, ,
, :
r e v e r s e (L) ->

97

f o l d ( fun (X, Acc ) -> [X| Acc ] end , [ ] , L) .


map2 (F , L) ->
r e v e r s e ( f o l d ( fun (X, Acc ) -> [ F(X) | Acc ] end , [ ] , L) ) .
f i l t e r 2 ( Pred , L) ->
F = fun (X, Acc ) ->
c a s e Pred (X) o f
t r u e -> [X| Acc ] ;
f a l s e -> Acc
end
end ,
r e v e r s e ( f o l d (F , [ ] , L) ) .

,
. , ?
, 
, Erlang (.
lists:map/2 , lists:lter/2 , lists:foldl/3 lists:foldr/3 .
all/2 any/2 , , true,
true, .
dropwhile/2 ,
, , , takewhile/2 ,
, ,
true. partition/2 .
, . , ,  . ,
atten/1 , atlength/1 , atmap/2 , merge/1 , nth/2 , nthtail/2 , split/2
.
,
zip- ( ), unzip-, ..
. . ,
, .

98

9

9.1

-!

. ,
,
, ,
. ,
.
, Erlang : (concurrent).
:
(, referntial transparency), ,
.. Erlang: ,
(concurrent) , ..
, , .
. ,
.
: Erlang ,
, , . 1 . ,
, .
99

9.2

: , , .
, .
: , (, , , ), ..
:

module.beam: Module name 'madule' does not match le name


'module'

, -module
.

./module.erl:2: Warning: function some_function/0 is unused

, . , , . !

./module.erl:2: function some_function/1 undened

.
-export , .
,
. - - , ,
.

./module.erl:5: syntax error before: 'SomeCharacterOrWord'

, : , ( , , case
). , ,
( !)

./module.erl:5: syntax error before:

, . , .
. .

100

./module.erl:5: Warning: this expression will fail with a 'badarith'


exception

Erlang , ,
Erlang .
, , (, llama + 5 ). ,
.

./module.erl:5: Warning: variable 'Var' is unused

. , .
, _
(-
_Var ). , ,
.

./module.erl:5: Warning: a term is constructed, but never used

, ,
, . ,
- - .

./module.erl:5: head mismatch

, . , . . ,
.

./module.erl:5: Warning: this clause cannot match because a


previous clause at line 4 always matches
, (catch-all)
(specic). , .

./module.erl:9: variable 'A' unsafe in 'case' (line 5)

, case. . . of , . . ,
MyVar = case . . . of . . .
, .
101

, ,
, . , , ,
, ,
. ,
. , ,
.
9.3

, !

.
:
( if- case-), ,
.. ,
-
.
, ,
,
Erlang , .
, TypEr Dialyzer ( 6.4 ), , ..
 . ,
, ,
.
, ,
, 50
. , , :
, .
9.4

(run-time errors) . .
Erlang ,
102

.
, .

function_clause

1> l i s t s : s o r t ( [ 3 , 2 , 1 ] ) .
[ 1 ,2 ,3 ]
2> l i s t s : s o r t ( f f f f f f f ) .
** e x c e p t i o n e r r o r : no f u n c t i o n c l a u s e matching l i s t s : s o r t (
fffffff )

,
.

case_clause
3> c a s e " Unexpected Value " o f
3>
e x p e c t e d _ v a l u e -> ok ;
3>
other_expected_value -> ' a l s o ok '
3> end .
** e x c e p t i o n e r r o r : no c a s e c l a u s e matching " Unexpected Value "

, - case , ,
(catch-all clause)!

if_clause
4> i f 2 > 4 -> ok ;
4>
0 > 1 -> ok
4> end .
** e x c e p t i o n e r r o r : no t r u e branch found when e v a l u a t i n g an i f
expression

case_clause . , true . , , , true .

badmatch
5> [ X,Y] = { 4 , 5 } .
** e x c e p t i o n e r r o r : no match o f r i g h t hand s i d e v a l u e { 4 , 5 }

, . ,
, , =
103

(, - ,
!). , , _MyVar
, _ . ,
 .
, , .
.

badarg
6> e r l a n g : b i n a r y _ t o _ l i s t ( "heh , a l r e a d y a l i s t " ) .
** e x c e p t i o n e r r o r : bad argument
i n f u n c t i o n b i n a r y _ t o _ l i s t /1
c a l l e d a s b i n a r y _ t o _ l i s t ( "heh , a l r e a d y a l i s t " )

function_clause ,
. ,
,
, ().
.

undef
7> l i s t s : random ( [ 1 , 2 , 3 ] ) .
** e x c e p t i o n e r r o r : u n d e f i n e d f u n c t i o n l i s t s : random /1

, . , ( ),
.
,
Erlang. . code:add_patha/1
code:add_pathz/1 . ,
, !

badarith
8> 5 + l l a m a .
** e x c e p t i o n e r r o r : bad argument i n an a r i t h m e t i c e x p r e s s i o n
i n o p e r a t o r +/2
c a l l e d as 5 + llama

, . ,
104

badfun
9> hhfuns : add ( one , two ) .
** e x c e p t i o n e r r o r : bad f u n c t i o n one
i n f u n c t i o n hhfuns : add /2

, .
hhfuns 8
- . , badfun .

badarity
10> F = fun (_) -> ok end .
#Fun<e r l _ e v a l .6.13229925 >
11> F( a , b ) .
** e x c e p t i o n e r r o r : i n t e r p r e t e d f u n c t i o n with a r i t y 1 c a l l e d with
two arguments

badarity  badfun . , , ( ) , .

system_limit

, system_limit : ( ),
, , ,
.. Erlang Eciency Guide
(system limits). : ,
.
9.5


,
, . Erlang : (errors),
105

(throws) (exits).
( ):
9.5.1

erlang:error(Reason)
,
,

.
,
,
.
(errors)
, . if_clause , ? , 
(, ). , ,
7. , , .
, . , ,
..
{ok, Value} ,
undened .
. :
1>
**
2>
**

erlang : error ( badarith ) .


e x c e p t i o n e r r o r : bad argument i n an a r i t h m e t i c e x p r e s s i o n
e r l a n g : e r r o r ( custom_error ) .
e x c e p t i o n e r r o r : custom_error

Erlang custom_error
bad argument in . . . ,
(
).

106

9.5.2

: (internal) (external). exit/1 .


exit/2 , (concurrent)
Erlang; ,
.
(errors). ,
exit/1 . . , ?
. ,
, .
,
. , -, , .

.
- .
, , , , ..

Erlang , .
107

; , ,
. ,
,
. ,
..

, ,
erlang:error/1 exit/1 . , .
, -
. ,
erlang:error/1 , exit/1
.
, , , ,
. .
9.5.3

 , ,
.
, !.
.
, ,
, .
:
1> throw ( p e r m i s s i o n _ d e n i e d ) .
** e x c e p t i o n throw : p e r m i s s i o n _ d e n i e d

permission_denied ( ' ' ,


- ,
).

. ssl .
throw/1 , {error, Reason}
. , ,
108

.
,
,
.
, . ,
, , . , default ,
.

.
, .
,
.
9.6

, , . try . . . catch .
try . . . catch - ,
, . :
try Expression of
S u c c e s s f u l P a t t e r n 1 [ Guards ] ->
Expression1 ;
S u c c e s s f u l P a t t e r n 2 [ Guards ] ->
Expression2
catch
TypeOfError : E x c e p t i o n P a t t e r n 1 ->
Expression3 ;
TypeOfError : E x c e p t i o n P a t t e r n 2 ->
Expression4
end .

, try of , . ,
, .
, try . . . of catch
109

case . . . of . catch TypeOfError error , throw exit ,


c ,
. , throw . .
exceptions .
:
- module ( e x c e p t i o n s ) .
- compile ( export_all ) .
throws (F) ->
try F() of
_ -> ok
catch
Throw -> { throw , caught , Throw}
end .

:
1> c ( e x c e p t i o n s ) .
{ok , e x c e p t i o n s }
2> e x c e p t i o n s : throws ( fun ( ) -> throw ( thrown ) end ) .
{ throw , caught , thrown }
3> e x c e p t i o n s : throws ( fun ( ) -> e r l a n g : e r r o r ( pang ) end ) .
** e x c e p t i o n e r r o r : pang

, try . . . catch (throws).


, ,
. catch-
:
e r r o r s (F) ->
try F() of
_ -> ok
catch
e r r o r : E r r o r -> { e r r o r , caught , E r r o r }
end .
e x i t s (F) ->
try F() of
_ -> ok
catch
e x i t : E x i t -> { e x i t , caught , E x i t }
end .

:
110

4> c ( e x c e p t i o n s ) .
{ok , e x c e p t i o n s }
5> e x c e p t i o n s : e r r o r s ( fun ( ) -> e r l a n g : e r r o r ( " Die ! " ) end ) .
{ e r r o r , caught , " Die ! " }
6> e x c e p t i o n s : e x i t s ( fun ( ) -> e x i t ( goodbye ) end ) .
{ e x i t , caught , goodbye }

try . . . catch . , :
sword ( 1 )
sword ( 2 )
sword ( 3 )
sword ( 4 )
sword ( 5 )

->
->
->
->
->

throw ( s l i c e ) ;
e r l a n g : e r r o r ( cut_arm ) ;
e x i t ( cut_leg ) ;
throw ( punch ) ;
exit ( cross_bridge ) .

b l a c k _ k n i g h t ( Attack ) when i s _ f u n c t i o n ( Attack , 0 ) ->


t r y Attack ( ) o f
_ -> "None s h a l l p a s s . "
catch
throw : s l i c e -> " I t i s but a s c r a t c h . " ;
e r r o r : cut_arm -> " I ' ve had worse . " ;
e x i t : c u t _ l e g -> "Come on you pansy ! " ;
_:_ -> " J u s t a f l e s h wound . "
end .

is_function/2 ,
, Attack 
0. :
t a l k ( ) -> " b l a h b l a h " .

- (MP):
7> c ( e x c e p t i o n s ) .
{ok , e x c e p t i o n s }
8> e x c e p t i o n s : t a l k ( ) .
" blah blah "
9> e x c e p t i o n s : b l a c k _ k n i g h t ( fun e x c e p t i o n s : t a l k / 0 ) .
"None s h a l l p a s s . "
10> e x c e p t i o n s : b l a c k _ k n i g h t ( fun ( ) -> e x c e p t i o n s : sword ( 1 )
" I t i s but a s c r a t c h . "
11> e x c e p t i o n s : b l a c k _ k n i g h t ( fun ( ) -> e x c e p t i o n s : sword ( 2 )
" I ' ve had worse . "
12> e x c e p t i o n s : b l a c k _ k n i g h t ( fun ( ) -> e x c e p t i o n s : sword ( 3 )
"Come on you pansy ! "
13> e x c e p t i o n s : b l a c k _ k n i g h t ( fun ( ) -> e x c e p t i o n s : sword ( 4 )
" J u s t a f l e s h wound . "

111

end ) .
end ) .
end ) .
end ) .

14> e x c e p t i o n s : b l a c k _ k n i g h t ( fun ( ) -> e x c e p t i o n s : sword ( 5 ) end ) .


" J u s t a f l e s h wound . "

9- , .
(, , ), ( slice , cut_arm , cut_leg ).
13 14 , ,
. _:_ , .
:
,
, .
, Erlang
.
try . . . catch , .
'nally', :
t r y Expr o f
P a t t e r n -> Expr1
catch
Type : E x c e p t i o n -> Expr2
a f t e r % t h i s always g e t s e x e c u t e d
Expr3
end

after , . , after . .
, , , ,
, .
Erlang catch. ! try of
, !
whoa ( ) ->

112

try

of

talk () ,
_Knight = "None s h a l l Pass ! " ,
_Doubles = [N*2 | | N <- l i s t s : s e q ( 1 , 1 0 0 ) ] ,
throw ( up ) ,
_WillReturnThis = t e q u i l a

t e q u i l a -> " hey t h i s worked ! "


catch
E x c e p t i o n : Reason -> { caught , Exception , Reason }
end .

exceptions:whoa() , , {caught, throw, up}


- throw(up) . , , try of
. . .
exceptions:whoa/0 ( ,
), ,
. of -
. , :
im_impressed ( ) ->
try
talk () ,
_Knight = "None s h a l l Pass ! " ,
_Doubles = [N*2 | | N <- l i s t s : s e q ( 1 , 1 0 0 ) ] ,
throw ( up ) ,
_WillReturnThis = t e q u i l a
catch
E x c e p t i o n : Reason -> { caught , Exception , Reason }
end .

- !

113

: , -

.
, .
try . . . catch of ,
,
( , 
Erlang). ,
. of catch ,
, .
try . . . of . . . catch
try . . . catch , .
, , . , , !
9.7

, ,
, Erlang .
catch , ,
.
, :
1> c a t c h throw ( whoa ) .
whoa
2> c a t c h e x i t ( d i e ) .
{ 'EXIT ' , d i e }
3> c a t c h 1 / 0 .
{ 'EXIT ' , { b a d a r i t h , [ { e r l a n g , ' / ' , [ 1 , 0 ] } ,
{ e r l _ e v a l , do_apply , 5 } ,
{ e r l _ e v a l , expr , 5 } ,
{ s h e l l , exprs , 6 } ,
{ s h e l l , eval_exprs , 6 } ,
{ s h e l l , eval_loop , 3 } ] } }
4> c a t c h 2+2.
4

114

, , {'EXIT', Reason} .
, ( ).
:
5> c a t c h d o e s n t : e x i s t ( a , 4 ) .
{ 'EXIT ' , { undef , [ { doesnt , e x i s t , [ a , 4 ] } ,
{ e r l _ e v a l , do_apply , 5 } ,
{ e r l _ e v a l , expr , 5 } ,
{ s h e l l , exprs , 6 } ,
{ s h e l l , eval_exprs , 6 } ,
{ s h e l l , eval_loop , 3 } ] } }

 undef . ,
(. ).
.
, ( {Module, Function, Arguments} ).
.
,  , . {Module, Function, Arity} .
-, .
, erlang:get_stacktrace/0 .
catch , (
exceptions.erl):
c a t c h e r (X,Y) ->
c a s e c a t c h X/Y o f
{ 'EXIT ' , { b a d a r i t h ,_} } -> "uh oh" ;
N -> N
end .

, :
6> c ( e x c e p t i o n s ) .
{ok , e x c e p t i o n s }
7> e x c e p t i o n s : c a t c h e r ( 3 , 3 ) .

115

1.0
8> e x c e p t i o n s : c a t c h e r ( 6 , 3 ) .
2.0
9> e x c e p t i o n s : c a t c h e r ( 6 , 0 ) .
"uh oh"

, catch . 
:
10> X = c a t c h 4+2.
* 1 : syntax e r r o r b e f o r e : ' catch '
10> X = ( c a t c h 4+2) .
6

, , , ,
. ,
:
11> c a t c h e r l a n g : boat ( ) .
{ 'EXIT ' , { undef , [ { e r l a n g , boat , [ ] } ,
{ e r l _ e v a l , do_apply , 5 } ,
{ e r l _ e v a l , expr , 5 } ,
{ s h e l l , exprs , 6 } ,
{ s h e l l , eval_exprs , 6 } ,
{ s h e l l , eval_loop , 3 } ] } }
12> c a t c h e x i t ( { undef , [ { e r l a n g , boat , [ ] } , { e r l _ e v a l , do_apply , 5 } ,
{ e r l _ e v a l , expr , 5 } , { s h e l l , exprs , 6 } , { s h e l l , eval_exprs , 6 } , {
s h e l l , eval_loop , 3 } ] } ) .
{ 'EXIT ' , { undef , [ { e r l a n g , boat , [ ] } ,
{ e r l _ e v a l , do_apply , 5 } ,
{ e r l _ e v a l , expr , 5 } ,
{ s h e l l , exprs , 6 } ,
{ s h e l l , eval_exprs , 6 } ,
{ s h e l l , eval_loop , 3 } ] } }

, , .
, ,
throw/1 . ,
throw/1 catch
:
one_or_two ( 1 ) -> r e t u r n ;
one_or_two ( 2 ) -> throw ( r e t u r n ) .

:
13> c ( e x c e p t i o n s ) .

116

{ok , e x c e p t i o n s }
14> c a t c h e x c e p t i o n s : one_or_two ( 1 ) .
return
15> c a t c h e x c e p t i o n s : one_or_two ( 2 ) .
return

catch , ,
!
,
try . . . catch R10B.
9.8

try

,
, tree . ,
, ,
. ,
. , ,
.
tree:lookup/2 , ,
. , ,  {node, {Key, Value, NodeLeft, NodeRight}} ,
{node, 'nil'} . ,
, :
%% l o o k s f o r a g i v e n v a l u e ' Val ' i n t h e t r e e .
has_value (_, { node , ' n i l ' } ) ->
false ;
has_value ( Val , { node , {_, Val , _, _} } ) ->
true ;
has_value ( Val , { node , {_, _, L e f t , Right } } ) ->
c a s e has_value ( Val , L e f t ) o f
t r u e -> t r u e ;
f a l s e -> has_value ( Val , Right )
end .

, ,
,
:

117

.
, :
has_value ( Val , Tree ) ->
t r y has_value1 ( Val , Tree ) o f
f a l s e -> f a l s e
catch
t r u e -> t r u e
end .
has_value1 (_, { node , ' n i l ' } ) ->
false ;
has_value1 ( Val , { node , {_, Val , _, _} } ) ->
throw ( t r u e ) ;
has_value1 ( Val , { node , {_, _, L e f t , Right } } ) ->
has_value1 ( Val , L e f t ) ,
has_value1 ( Val , Right ) .

, ,
, ,
. .
. , ,
catch . , false,
:

, ,
. , 118

,
, . 
,
.
, ,
Erlang.

119

10


, ,
- . .
.
Miran- Learn You a Haskell.
, Erlang Haskell .
, , , ,
, .
,
.
10.1

,
( (2 + 2) / 5 ).
, ,
, . : . ( ), .
, ,
. (2 + 2) / 5
120

(/ (+ 2 2) 5) . , + /
, (/ (+ 2 2) 5) / + 2 2 5 .
, ( ), :
. , ,
2 2 + 5 / . : 9 * 5 + 7 10 * 2 * (3 + 5) / 2
9 5 * 7 10 2 * 3 4 + * 2 / .
, .
.
.
, ,
. : , , .

10 4 3 + 2
10 (4 3 +) 2
10 ((4 3 +) 2 )
(10 ((4 3 +) 2 ))
(10 (7 2 ))
(10 14 )
4
,
. 10 4 3 + 2 * - . 10.
. 4. .
3. .
:

+ . 2. ,
, :
121

7 (,
, !) [7, 10], 2 * - .
2 .
* , .
:

14 . - , . ! . !

. - . , ,
.
, .. Wikipedia.
, Erlang . ,  .
. . calc.erl.
. , , :
10 4 3 + 2 * - . ,
122

, . , [10,4,3,+,2,*,-] .
, string:tokens/2 , :
1> s t r i n g : t o k e n s ( " 10 4 3 + 2 * - " , " " ) .
[ " 10 " , " 4 " , " 3 " , "+" , " 2 " , " * " , " - " ]

.
. ? , , Erlang .
( | ) [Head|Tail]
Head ( Tail ).
.
,
, . .  .  , . ,
.
(fold)!
, , lists:foldl/3
. ,
:
, , .
calc.erl . , ,
:
- module ( c a l c ) .
- e x p o r t ( [ rpn /1 ] ) .
rpn (L) when i s _ l i s t (L) ->
[ Res ] = l i s t s : f o l d l ( fun rpn / 2 , [ ] , s t r i n g : t o k e n s (L , " " ) ) ,
Res .

rpn/2 . :
,
123

. .
[Res] Res.
, . rpn/2
.
, , rpn(Op,Stack) , [NewVal|Stack] .
:
rpn (X, Stack ) -> [ r e a d (X) | Stack ] .

read/1
. , Erlang ,
, :
r e a d (N) ->
c a s e s t r i n g : t o _ f l o a t (N) o f
{ e r r o r , n o _ f l o a t } -> l i s t _ t o _ i n t e g e r (N) ;
{F ,_} -> F
end .

string:to_oat/1 13.37
. , {error,no_oat} .
list_to_integer/1 .
rpn/2 . . (. 5.1), . ,
,
. :
rpn ( "+" , [ N1 , N2 | S ] ) -> [ N2+N1 | S ] ;
rpn (X, Stack ) -> [ r e a d (X) | Stack ] .

, + ,
(N1,N2), . ,
. , :
1> c ( c a l c ) .
{ok , c a l c }
2> c a l c : rpn ( " 3 5 +" ) .

124

8
3> c a l c : rpn ( " 7 3 + 5 +" ) .
15

 .
:
rpn ( "+" , [ N1 , N2 | S ] ) -> [ N2+N1 | S ] ;
rpn ( " - " , [ N1 , N2 | S ] ) -> [ N2 - N1 | S ] ;
rpn ( " * " , [ N1 , N2 | S ] ) -> [ N2*N1 | S ] ;
rpn ( " / " , [ N1 , N2 | S ] ) -> [ N2/N1 | S ] ;
rpn ( "^" , [ N1 , N2 | S ] ) -> [ math : pow (N2 , N1) | S ] ;
rpn ( " l n " , [N| S ] )
-> [ math : l o g (N) | S ] ;
rpn ( " l o g 1 0 " , [N| S ] ) -> [ math : l o g 1 0 (N) | S ] ;
rpn (X, Stack ) -> [ r e a d (X) | Stack ] .

, ,
( ),
.
'sum' 'prod', , ,
. , calc.erl .
-, ,
. = Erlang
(assertion). ,  . , . , Erlang
, Common Test
EUnit. , = .
r p n _ t e s t ( ) ->
5 = rpn ( " 2 3 +" ) ,
87 = rpn ( " 90 3 - " ) ,
-4 = rpn ( " 10 4 3 + 2 * - " ) ,
- 2 . 0 = rpn ( " 10 4 3 + 2 * - 2 / " ) ,
ok = t r y
rpn ( " 90 34 12 33 55 66 + * - +" )
catch
e r r o r : {badmatch , [_|_] } -> ok
end ,
4037 = rpn ( " 90 34 12 33 55 66 + * - + - " ) ,
8 . 0 = rpn ( " 2 3 ^" ) ,
t r u e = math : s q r t ( 2 ) == rpn ( " 2 0 . 5 ^" ) ,
t r u e = math : l o g ( 2 . 7 ) == rpn ( " 2 . 7 l n " ) ,
t r u e = math : l o g 1 0 ( 2 . 7 ) == rpn ( " 2 . 7 l o g 1 0 " ) ,
50 = rpn ( " 10 10 10 20 sum" ) ,
1 0 . 0 = rpn ( " 10 10 10 20 sum 5 / " ) ,

125

1 0 0 0 . 0 = rpn ( " 10 10 20 0 . 5 prod " ) ,


ok .

. , . . , .
try . . . catch , badmatch, :
90 34 12 33 55 66 + * - +
90 ( 3 4 ( 1 2 ( 3 3 ( 5 5 66 +) * ) - ) +)

rpn/1 -3947 90 , ,
90. : , (
), ,
. Erlang ,
,
. [Res] rpn/1 . , , 
.
true = FunctionCall1 == FunctionCall2 , = . ,
true.
sum prod,
. ,
:
1> c ( c a l c ) .
{ok , c a l c }
2> c a l c : r p n _ t e s t ( ) .
ok
3> c a l c : rpn ( " 1 2 ^ 2 2 ^ 3 2 ^ 4 2 ^ sum 2 - " ) .
28.0

28 sum(12 + 22 + 32 + 42 ) 2 .
, badarith - - .
126

, badmatch , .
calc.
10.2

Learn You a Haskell. ,


.
. , .
,
. ,
- , ,
. , , , , . ,
:

-
Erlang-, , ,
. , road.txt :
50
10
30
5
90
20
40
2
25
10
8
0

127

: A1, B1, X1, A2, B2, X2, ..., An, Bn, Xn


x  , B.
x 0, .
3 () {A,B,X} .
,
, Erlang.
, .
. , ,
A, B ( x,
, ):

, : A
B. , ,
, A B.
:

, ! {5,1,3}
A B? , A. A1 A2 (
A1 ), A1 (5),
B1 (1), X1 (3).
(5) (4).
[B, X] . B? A1 (5),
X1 (3), B1 (1).
128

! 4 [B, X] ,
1 [B] B1 B2.
A ( A2 X2 )
B ( B2 X2 ).
, . ,
. , !
, . A A2 [B, X] , 14 ( 14 = 4 + 10 ,
B2, X2 [B] , 16 ( 16 = 1 + 15 + 0 ).
, [B, X, A] [B, B, X] .

B A2
[B, X] X2, 14 ( 14 = 4 + 10 + 0 ).
B2 [B], 16 ( 16 = 1 + 15 ).
: [B, X, A, X] .
A B. 14.
. ,
X 0.
, .
, .
,
. , , ,
, ,
. (fold).

129

: ,

,
. ,
(dictionaries), , ..

(maps) (folds). , .
, ? , ! , . .
,
( , ,
..)
/
/ , le:open/2 le:close/1 ,
, ( !)
le:read/2 ( ), le:read_line/1 , le:position/3
..
, le:read_le/1
( ), le:consult/1
( Erlang) le:pread/2 ( , ) pwrite/2
( ).
, road.txt. , , le:read_le("road.txt"). :
1> {ok , Binary } = f i l e : r e a d _ f i l e ( " road . t x t " ) .
{ok,<<" 50\ r \ n10 \ r \ n30 \ r \n5\ r \ n90 \ r \ n20 \ r \ n40 \ r \n2\ r \ n25 \ r \ n10 \ r \
n8\ r \n0\ r \n">>}
2> S = s t r i n g : t o k e n s ( b i n a r y _ t o _ l i s t ( Binary ) , " \ r \n\ t " ) .
[ " 50 " , " 10 " , " 30 " , " 5 " , " 90 " , " 20 " , " 40 " , " 2 " , " 25 " , " 10 " , "8 " , " 0 " ]

, (   )
( \t ) , "50 10 30 5 90 20 40 2 25 10 8 0".
, 130

. , ,
:
3> [ l i s t _ t o _ i n t e g e r (X) | | X <- S ] .
[ 50 ,10 ,30 ,5 ,90 ,20 ,40 ,2 ,25 ,10 ,8 ,0 ]

, road.erl
:
- module ( road ) .
- compile ( export_all ) .
main ( ) ->
F i l e = " road . t x t " ,
{ok , Bin } = f i l e : r e a d _ f i l e ( F i l e ) ,
parse_map ( Bin ) .
parse_map ( Bin ) when i s _ b i n a r y ( Bin ) ->
parse_map ( b i n a r y _ t o _ l i s t ( Bin ) ) ;
parse_map ( S t r ) when i s _ l i s t ( S t r ) ->
[ l i s t _ t o _ i n t e g e r (X) | | X <- s t r i n g : t o k e n s ( Str , " \ r \n\ t " ) ] .

main/0
parse_map/1 . le:read_le/1 , . ,
parse_map/1 ,
. , (
).
, , {A,B,X} , . , 3
, :
group_vals ( [ ] , Acc ) ->
l i s t s : r e v e r s e ( Acc ) ;
group_vals ( [ A, B,X| Rest ] , Acc ) ->
group_vals ( Rest , [ {A, B,X} | Acc ] ) .

.
parse_map/1 :
parse_map ( Bin ) when i s _ b i n a r y ( Bin ) ->
parse_map ( b i n a r y _ t o _ l i s t ( Bin ) ) ;

131

parse_map ( S t r ) when i s _ l i s t ( S t r ) ->


Values = [ l i s t _ t o _ i n t e g e r (X) | | X <- s t r i n g : t o k e n s ( Str , " \ r \n\
t ") ] ,
group_vals ( Values , [ ] ) .

, :
1> c ( road ) .
{ok , road }
2> road : main ( ) .
[ { 50 ,10 ,30 } , { 5 ,90 ,20 } , { 40 ,2 ,25 } , { 10 ,8 ,0 } ]

, . ,
. .
: , . , ( {5,90,20} ). ,
. , ,
, . , A:

132

B :

, A 
[B,X] . , 40.
B  [B] 10. , A B, , .
, . ( A,
B) , {{DistanceA, PathA}, {DistanceB, PathB}} .
, ,
, .
:
{A,B,X} {{DistanceA,PathA}, {DistanceB,PathB}} .
:
s h o r t e s t _ s t e p ( {A, B,X} , { { DistA , PathA} , { DistB , PathB} } ) ->
OptA1 = { DistA + A, [ {a ,A} | PathA ] } ,
OptA2 = { DistB + B + X, [ {x ,X} , {b , B} | PathB ] } ,
OptB1 = { DistB + B, [ {b , B} | PathB ] } ,
OptB2 = { DistA + A + X, [ {x ,X} , {a ,A} | PathA ] } ,
{ e r l a n g : min ( OptA1 , OptA2 ) , e r l a n g : min ( OptB1 , OptB2 ) } .

OptA1 A ( A), OptA2  (


B, X ). B
OptB1 OptB2.
.
, [{x,X}] [x] ,
133

. ,
( {x,X} {b,B} ).
- , :
-,
.
, , erlang:min/2 , .
, : Erlang ! ,
, .
:
optimal_path (Map) ->
{A, B} = l i s t s : f o l d l ( fun s h o r t e s t _ s t e p / 2 , { { 0 , [ ] } , { 0 , [ ] } } ,
Map) ,
{ _Dist , Path } = i f hd ( e l e m e n t ( 2 ,A) ) =/= {x , 0 } -> A;
hd ( e l e m e n t ( 2 ,B) ) =/= {x , 0 } -> B
end ,
l i s t s : r e v e r s e ( Path ) .

, , {x,0} . if , {x,0} .
( length/1 ).
, -
( ,
).
, . main optimal_path/1 .
main ( ) ->
F i l e = " road . t x t " ,
{ok , Bin } = f i l e : r e a d _ f i l e ( F i l e ) ,
optimal_path ( parse_map ( Bin ) ) .

, -! ! !
1> c ( road ) .
{ok , road }
2> road : main ( ) .
[ {b , 1 0 } , {x , 3 0 } , {a , 5 } , {x , 2 0 } , {b , 2 } , {b , 8 } ]

? Erlang. main:
134

main ( [ FileName ] ) ->


{ok , Bin } = f i l e : r e a d _ f i l e ( FileName ) ,
Map = parse_map ( Bin ) ,
i o : format ( "~p~n" , [ optimal_path (Map) ] ) ,
erlang : halt () .

main 1.
. erlang:halt/0 ,
Erlang ,
optimal_path/1 io:format/2 , Erlang
.
road.erl ( ):
- module ( road ) .
- compile ( export_all ) .
main ( [ FileName ] ) ->
{ok , Bin } = f i l e : r e a d _ f i l e ( FileName ) ,
Map = parse_map ( Bin ) ,
i o : format ( "~p~n" , [ optimal_path (Map) ] ) ,
erlang : halt (0) .
%% Transform a s t r i n g i n t o a r e a d a b l e map o f t r i p l e s
parse_map ( Bin ) when i s _ b i n a r y ( Bin ) ->
parse_map ( b i n a r y _ t o _ l i s t ( Bin ) ) ;
parse_map ( S t r ) when i s _ l i s t ( S t r ) ->
Values = [ l i s t _ t o _ i n t e g e r (X) | | X <- s t r i n g : t o k e n s ( Str , " \ r \n\
t ") ] ,
group_vals ( Values , [ ] ) .
group_vals ( [ ] , Acc ) ->
l i s t s : r e v e r s e ( Acc ) ;
group_vals ( [ A, B,X| Rest ] , Acc ) ->
group_vals ( Rest , [ {A, B,X} | Acc ] ) .
%% P i c k s t h e b e s t o f a l l paths , woo !
optimal_path (Map) ->

135

{A, B} = l i s t s : f o l d l ( fun s h o r t e s t _ s t e p / 2 , { { 0 , [ ] } , { 0 , [ ] } } ,
Map) ,
{ _Dist , Path } = i f hd ( e l e m e n t ( 2 ,A) ) =/= {x , 0 } -> A;
hd ( e l e m e n t ( 2 ,B) ) =/= {x , 0 } -> B
end ,
l i s t s : r e v e r s e ( Path ) .
%% a c t u a l problem s o l v i n g
%% change t r i p l e s o f t h e form {A, B,X}
%% where A, B,X a r e d i s t a n c e s and a , b , x a r e p o s s i b l e p a t h s
%% t o t h e form { DistanceSum , P a t h L i s t } .
s h o r t e s t _ s t e p ( {A, B,X} , { { DistA , PathA} , { DistB , PathB} } ) ->
OptA1 = { DistA + A, [ {a ,A} | PathA ] } ,
OptA2 = { DistB + B + X, [ {x ,X} , {b , B} | PathB ] } ,
OptB1 = { DistB + B, [ {b , B} | PathB ] } ,
OptB2 = { DistA + A + X, [ {x ,X} , {a ,A} | PathA ] } ,
{ e r l a n g : min ( OptA1 , OptA2 ) , e r l a n g : min ( OptB1 , OptB2 ) } .

:
$ e r l c road . e r l
$ e r l - n o s h e l l - run road main road . t x t
[ {b , 1 0 } , {x , 3 0 } , {a , 5 } , {x , 2 0 } , {b , 2 } , {b , 8 } ]

, !
. bash/bat ,
escript.
,
, , , .
,
. , ,
. ,
.

136

11


11.1

, !

Erlang , , ,
. , , ,
,
, . , . ,
, !
, , :
, ,
( ), , , ,
.. , , . ,
Erlang.
11.2

,  .  - , , . . ,
137

,
. Erlang C ( C).
:
- module ( r e c o r d s ) .
- compile ( export_all ) .
- r e c o r d ( robot , {name ,
type=i n d u s t r i a l ,
hobbies ,
d e t a i l s=[ ] } ) .

4 :
, , . ,
, , :
industrial [] . records :
f i r s t _ r o b o t ( ) ->
#r o b o t {name=" Mechatron " ,
type=handmade ,
d e t a i l s=[ "Moved by a s m a l l man i n s i d e " ] } .

:
1> c ( r e c o r d s ) .
{ok , r e c o r d s }
2> r e c o r d s : f i r s t _ r o b o t ( ) .
{ robot , " Mechatron " , handmade , u n d e f i n e d ,
[ "Moved by a s m a l l man i n s i d e " ] }

! ! Erlang  . , .
Erlang rr(Module) , Module :
3> r r ( r e c o r d s ) .
[ robot ]
4> r e c o r d s : f i r s t _ r o b o t ( ) .
#r o b o t {name = " Mechatron " , type = handmade ,
hobbies = undefined ,
d e t a i l s = [ "Moved by a s m a l l man i n s i d e " ] }

! .
, rst_robot/0 hobbies ,
. Erlang undened.
138

, , robot :
c a r _ f a c t o r y ( CorpName ) ->
#r o b o t {name=CorpName , h o b b i e s=" b u i l d i n g c a r s " } .

:
5> c ( r e c o r d s ) .
{ok , r e c o r d s }
6> r e c o r d s : c a r _ f a c t o r y ( " Jokeswagen " ) .
#r o b o t {name = " Jokeswagen " , type = i n d u s t r i a l ,
hobbies = " building cars " , d e t a i l s = [ ] }

, .

: rr() ,
( rr(*) ) .
,
: rd(Name, Denition)
-record(Name, Denition) , . rf() , rf(Name) rf([Names]) 
.
rl()
,
rl(Name) rl([Names]) .
, , rp(Term) ( , ).
.
. . 
. ,
:
5> Crusher = #r o b o t {name=" Crusher " , h o b b i e s=[ " Crushing p e o p l e " , "
petting cats " ] } .
#r o b o t {name = " Crusher " , type = i n d u s t r i a l ,
h o b b i e s = [ " Crushing p e o p l e " , " p e t t i n g c a t s " ] ,
details = [ ]}
6> Crusher#r o b o t . h o b b i e s .
[ " Crushing p e o p l e " , " p e t t i n g c a t s " ]

139

. ,  . . , , . #robot 
Crusher#robot.hobbies . , , ,
. :
7> NestedBot = #r o b o t { d e t a i l s=#r o b o t {name=" e r N e s t " } } .
#r o b o t {name = u n d e f i n e d , type = i n d u s t r i a l ,
hobbies = undefined ,
d e t a i l s = #r o b o t {name = " e r N e s t " , type = i n d u s t r i a l ,
hobbies = undefined , d e t a i l s = [ ] }}
8> ( NestedBot#r o b o t . d e t a i l s )#r o b o t . name .
" erNest "

, .

R14A
. NestedBot NestedRobot#robot.details#robot.name . .
, :
9> #r o b o t . type .
3

 ,
.
, :
- r e c o r d ( u s e r , { id , name , group , age } ) .
%% u s e p a t t e r n matching t o f i l t e r
admin_panel(# u s e r {name=Name , group=admin} ) ->
Name ++ " i s a l l o w e d ! " ;
admin_panel(# u s e r {name=Name} ) ->
Name ++ " i s not a l l o w e d " .
%% can extend u s e r w i t h o u t problem
a d u l t _ s e c t i o n (U = #u s e r { } ) when U#u s e r . age >= 18 ->
%% Show s t u f f t h a t can ' t be w r i t t e n i n such a t e x t
allowed ;
a d u l t _ s e c t i o n (_) ->

140

%% r e d i r e c t t o sesame s t r e e t s i t e
forbidden .

admin_panel/1 ,
( ). , adult_section/1 , SomeVar = #some_record{} . , , :
10> c ( r e c o r d s ) .
{ok , r e c o r d s }
11> r r ( r e c o r d s ) .
[ robot , u s e r ]
12> r e c o r d s : admin_panel(# u s e r { i d =1, name=" f e r d " , group=admin , age
=96} ) .
" ferd i s allowed ! "
13> r e c o r d s : admin_panel(# u s e r { i d =2, name=" you " , group=u s e r s , age
=66} ) .
" you i s not a l l o w e d "
14> r e c o r d s : a d u l t _ s e c t i o n (# u s e r { i d =21 , name=" B i l l " , group=u s e r s ,
age=72} ) .
allowed
15> r e c o r d s : a d u l t _ s e c t i o n (# u s e r { i d =22 , name="Noah" , group=u s e r s ,
age=13} ) .
forbidden

,
,
.
,
. , :
function({record, _, _, ICareAboutThis, _, _}) -> . . . . - , - (
)
, .
(
):
repairman ( Rob ) ->
D e t a i l s = Rob#r o b o t . d e t a i l s ,
NewRob = Rob#r o b o t { d e t a i l s=[ " R ep air ed by repairman " | D e t a i l s ] }
,
{ r e p a i r e d , NewRob} .

141

:
16> c ( r e c o r d s ) .
{ok , r e c o r d s }
17> r e c o r d s : repairman(# r o b o t {name=" U l b e r t " , h o b b i e s=[ " t r y i n g t o
have f e e l i n g s " ] } ) .
{ r e p a i r e d ,# r o b o t {name = " U l b e r t " , type = i n d u s t r i a l ,
h o b b i e s = [ " t r y i n g t o have f e e l i n g s " ] ,
d e t a i l s = [ " Re pai red by repairman " ] } }

, .
. , ( Rob#robot{Field=NewValue} ), ,
erlang:setelement/3 .
, ,
. Erlang

. Erlang
C. , , . records.hrl
:
%% t h i s i s a . h r l ( h e a d e r ) f i l e .
- r e c o r d ( i n c l u d e d , { some_field ,
some_default = " yeah ! " ,
unimaginative_name } ) .

records.erl, :
- include (" records . hrl ") .

:
i n c l u d e d ( ) -> #i n c l u d e d { s o m e _ f i e l d="Some v a l u e " } .

, , :
18> c ( r e c o r d s ) .
{ok , r e c o r d s }
19> r r ( r e c o r d s ) .
[ i n c l u d e d , robot , u s e r ]
20> r e c o r d s : i n c l u d e d ( ) .
#i n c l u d e d { s o m e _ f i e l d = "Some v a l u e " , some_default = " yeah ! " ,
unimaginative_name = u n d e f i n e d }

! . , , ,
. ,
142

, , ,
.
:
. .hrl ,
, .
, , , . ,
-
 ,
, . ,
,
.
11.3

- .
: ,
.
,
. ,  , .
. . , - Erlang -
. , . .
. proplist ( ). Proplist 
[{Key, Value}] . , , . .
,
. , . proplist-
proplists. proplists:delete/2 ,
proplists:get_value/2 , proplists:get_all_values/2 , proplists:lookup/2
143

proplists:lookup_all/2 .
, . , proplist- .
, ( [NewElement|OldList] ) , ,
lists:keyreplace/4 .
,
. proplist-,
- . Proplist-
. ,
. proplists  -
.
- c ,
orddict  . Orddict- ( ) 
proplist- . , .. CRUD-
orddict:store/3 , orddict:nd/2 ( , ,
), orddict:fetch/2 ( ,
, )
orddict:erase/2 .
Orddict-
, , 75 (
). , -

-.
, / : dicts gb_trees.
orddict-: dict:store/3 , dict:nd/2 , dict:fetch/2 , dict:erase/2
, dict:map/2 dict:fold/2 (
).
144

orddict  .
, . , gb_trees : ( (smart) ),
, -
( (naive) ). gb_trees:enter/2 , gb_trees:lookup/2
gb_trees:delete_any/2 .
gb_trees:insert/3 , gb_trees:get/2 , gb_trees:update/3 gb_trees:delete/2 .
gb_trees:map/2 ,
.
, , , ( ),
.
- (
, ).
,
.
.
- gb_trees dict?
. , , gb_trees dicts
.
, dicts
, gb_trees . c , ,
.
, , dicts (fold),
gb_trees  . gb_trees -,
, gb_trees:next(Iterator)
. gb_trees
fold, . gb_trees
gb_trees:smallest/1 gb_trees:largest/1 .
, -,
. 145

,
- : , .
, , ,
.
: -
. ETS , DETS
mnesia. ,
. ,
.
11.4

, , ? . , .
.

, Erlang
.
, , ,
Erlang
.
, , ,
Ports. . C-Nodes,
Linked in drivers NIF ( R13B03+).
,
0 ( ).
. .
11.5

146

-
,
.
, , , . - ,
 , .

: , ,
, .. ,
, , .
( , ), , .
Erlang 4 , . ,
,
. : ordsets, sets,
gb_sets sofs ( ):

147

ordsets

Ordset- . , ,
 . .
: ordsets:new/0 ,
ordsets:is_element/2 ,

ordsets:add_element/2 ,

ordsets:del_element/2 ,

ordsets:union/1 , ordsets:intersection/1 .

sets

sets , ,
dict . Sets ,
ordsets, .
, , ,
- .

gb_sets

,
, gb_trees. gb_sets sets
gb_tree dict.
, .
gb_sets , sets ordsets,
. gb_trees
(smart) (naive) , ,
..

sofs

(sofs) , .
, ,
, ..
,
,
.

148

, , ,
. ,
gb_sets, ordsets sofs  ==
. 2 2.0
.
, sets =:= . .
,
, ,
.
. Bjorn
Gustavsson Erlang/OTP, Wings3D,
gb_sets; ordset ,
; sets ,
=:= ().
, , ,
.
11.6

( ,
,
): . , ,
, .
Erlang : digraph digraph_utils. digraph
: , .. digraph_utils
( , ),
, , .
 sofs
, .

149

11.7

queue FIFO (First In, First Out)


: : (

),
.
queue , ( API) . API, API, Okasaki API:

150

API

API ,
. : new/0 , in/2 , out/1 .
,
, -
..

API

API, , ,
, .
, ,
(. get/1 peek/1 ), ,
( drop/1 ), .. ,
, .

Okasaki API

Okasaki API . Chris Okasaki Purely


Functional Data Structures. API ,
,
-, API .
, API,
.
, , . , , , .
, ,
queue ( , ! !)
11.8

Erlang.
,
. , , ,
. , , ,
151

Erlang, .
.
,
(sequential) () Erlang.
, Erlang - ,
. , Erlang
. : , , . , -
, .
, ,
Erlang .

. !

152

12

- 21- ,
, .

, - ,
- - .
,  :
, , , . , , , , ,
.
. , - , .
- ,
.
.
: 
. , . !

153

12.1

. ( ,
, ) Erlang. , - . ,

, ,
,
.
, ,
. ,
,
, 12.4
, ( ).
, Erlang . ,
. ,
.
.
Erlang .

, ,
. , . computer science
, . ,
, -
.
Erlang , , . Erlang , ,
.
, , .
154

,
.
.

(
), Erlang .

.
, Erlang
,
. Erlang
(symmetric multiprocessing)
,
R13B 2009 . SMP,
.
SMP ,
.
,
, - . ,
Erlang ,
VM, .
12.2

, Erlang
,
, Erlang

,
. ,
, ,
, . ,
Erlang,
, . PLEX,
Ericsson, AXE. Erlang
155

, .
, Erlang , .
.

, .
12.2.1

.
, . , ( , ..).
, , .
, ,
, ,
. , , .
,
( ,
). ,
, .
 , . : , .
,
(, ). , , . .
.
. ,
, , .
(
) . 156

,
.
, .
12.2.2

, Erlang: . Erlang , . ,
. 
. ,
, .
, , , . , ,
( ). , , (). , , , ,
,
.
,
.  (, ).
, . ,
, . ,
(shared-nothing) (single assignment)
( ),
( ,
,
), ,
, Erlang. ,
Erlang ,
, .
.
157

,
( 14 ), ,
.
,
.  . , -
, ? ,
, , - , . ,
. . , .
. .

. , ( ) ,
, .

. -
,
. .
?
, ,
. C , ,
.
, ,
. ,
, ,
, . , , -
- , 158

. , . .
, . ,
, ,
.
12.2.3

, , Erlang.
? , -, .
,
. , ,
Erlang. VM, Erlang . Erlang
300 , .
.
, , VM . (scheduler). (run queue),
Erlang, . - , . Erlang
,
. ,
, .
.
Erlang
159

. ,
, , ,
4 , ? . ,
,
(linear scaling) (. ). ,
( ,
- ).
12.3

-
, - . , , ,
(embarassingly parallel). , (ray-tracing) ( 3D ),
, ..
IRC , , Erlang , GPU.
,
: , . Erlang
.
, Erlang,
.
-, , -, , ,
,
(- ?). ,
.

. ,
. , .
160

.
, .
, .
,
, ,
.
, , , ,
.
.
, ,
:

, 50% , 95% 20 ,
. ,
, , - .
161

.
.
, 100% , .

(ring benchmark). .
, .

, Erlang
,
.
, ,
.
, , , ,
.
( $ erl -smp disable ).
12.4

, !

, Erlang:
, .
, -
, .
. , . . , , ,
. (
, , ), .
Erlang spawn/1 ,
.
1> F = fun ( ) -> 2 + 2 end .
#Fun<e r l _ e v a l .20.67289768 >

162

2> spawn (F) .


<0.44.0 >

spawn/1 ( <0.44.0> ),
(process identier),
PID, Pid pid.
, , ( ) - . ,
.
, , , F. pid. ,
.
F?
. :
3> spawn ( fun ( ) -> i o : format ( "~p~n" , [ 2 + 2 ] ) end ) .
4
<0.46.0 >

, Erlang. , , io:format/2 .
10
timer:sleep/1 . N, N . .
4> G = fun (X) -> t i m e r : s l e e p ( 1 0 ) , i o : format ( "~p~n" , [X] ) end .
#Fun<e r l _ e v a l .6.13229925 >
5> [ spawn ( fun ( ) -> G(X) end ) | | X <- l i s t s : s e q ( 1 , 1 0 ) ] .
[ <0.273.0 > , <0.274.0 > , <0.275.0 > , <0.276.0 > , <0.277.0 > ,
<0.278.0 > , <0.279.0 > , <0.280.0 > , <0.281.0 > , <0.282.0 > ]
2
1
4
3
5
8
7
6
10
9

163

? . , . Erlang
,
. Erlang ,
, .
, . .
: , .
, Erlang
$ erl -smp disable .
, SMP ,
VM - . :
[smp:2:2] [rq:2],
SMP, 2 (rq, )
. [rq:1], SMP .
 [smp:2:2] ,
. [rq:2] , .
Erlang , .
R13B,
.
.
, , self/0 , pid :
6> s e l f ( ) .
<0.41.0 >
7> e x i t ( s e l f ( ) ) .
** e x c e p t i o n e x i t : <0.41.0 >
8> s e l f ( ) .
<0.285.0 >

pid - . .
. , 164

,
, (
, ).
:
! , bang -. pid ,
Erlang. , pid, :
9> s e l f ( ) ! h e l l o .
hello

,
. hello , .
:
10> s e l f ( ) ! s e l f ( ) ! d o u b l e .
double

self() ! (self() ! double) . : , . . ,


, , .

ush() :
11> f l u s h ( ) .
S h e l l got h e l l o
S h e l l got double
S h e l l got double
ok

165

 . ,
,
, , .
, , , -, .
receive .  ,
:
- module ( d o l p h i n s ) .
- compile ( export_all ) .
d o l p h i n 1 ( ) ->
receive
do_a_flip ->
i o : format ( "How about no?~n" ) ;
f i s h ->
i o : format ( "So l o n g and thanks f o r a l l t h e f i s h ! ~n" ) ;
_ ->
i o : format ( "Heh , we ' r e s m a r t e r than you humans . ~ n" )
end .

, receive case. . . of . , , receive


case of , ,
. receive :
receive
P a t t e r n 1 when Guard1 -> Expr1 ;
P a t t e r n 2 when Guard2 -> Expr2 ;
P a t t e r n 3 -> Expr3
end

, :
11> c ( d o l p h i n s ) .
{ok , d o l p h i n s }
12> Dolphin = spawn ( d o l p h i n s , d o l p h i n 1 , [ ] ) .
<0.40.0 >
13> Dolphin ! "oh , h e l l o d o l p h i n ! " .
Heh , we ' r e s m a r t e r than you humans .
"oh , h e l l o d o l p h i n ! "
14> Dolphin ! f i s h .
fish
15>

166


spawn/3 . spawn ,
, .
:
1. receive .
, ;
2. oh, hello dolphin!. do_a_ip . , sh ,
. , ( _ ) .
3. Heh, we're smarter than you humans.
,
, <0.40.0> .
- , Heh, we're smarter than you
humans. , . :
8> f ( Dolphin ) .
ok
9> Dolphin = spawn ( d o l p h i n s , d o l p h i n 1 , [ ] ) .
<0.53.0 >
10> Dolphin ! f i s h .
So l o n g and thanks f o r a l l t h e f i s h !
fish

.
, io:format/2
? , ! ( ?) , ,
, . .
. , ,
. Erlang pid
. , : {Pid, Message} . , :
d o l p h i n 2 ( ) ->
receive
{From , do_a_flip } ->

167

end .

From ! "How about no ? " ;


{From , f i s h } ->
From ! "So l o n g and thanks f o r a l l t h e f i s h ! " ;
_ ->
i o : format ( "Heh , we ' r e s m a r t e r than you humans . ~ n" )

, do_a_ip sh .
From.
.
11> c ( d o l p h i n s ) .
{ok , d o l p h i n s }
12> Dolphin2 = spawn ( d o l p h i n s , d o l p h i n 2 , [ ] ) .
<0.65.0 >
13> Dolphin2 ! { s e l f ( ) , do_a_flip } .
{ <0.32.0 > , do_a_flip }
14> f l u s h ( ) .
S h e l l g o t "How about no ? "
ok

. (
),
. .
, .
dolphin3/0 :
d o l p h i n 3 ( ) ->
receive
{From , do_a_flip } ->
From ! "How about no ? " ,
dolphin3 () ;
{From , f i s h } ->
From ! "So l o n g and thanks f o r a l l t h e f i s h ! " ;
_ ->
i o : format ( "Heh , we ' r e s m a r t e r than you humans . ~ n" ) ,
dolphin3 ()
end .

, do_a_ip
dolphin3/0 . ,
, . -
,
. sh 
:
168

15> Dolphin3 = spawn ( d o l p h i n s , d o l p h i n 3 , [ ] ) .


<0.75.0 >
16> Dolphin3 ! Dolphin3 ! { s e l f ( ) , do_a_flip } .
{ <0.32.0 > , do_a_flip }
17> f l u s h ( ) .
S h e l l g o t "How about no ? "
S h e l l g o t "How about no ? "
ok
18> Dolphin3 ! { s e l f ( ) , unknown_message} .
Heh , we ' r e s m a r t e r than you humans .
{ <0.32.0 > , unknown_message}
19> Dolphin3 ! Dolphin3 ! { s e l f ( ) , f i s h } .
{ <0.32.0 > , f i s h }
20> f l u s h ( ) .
S h e l l g o t "So l o n g and thanks f o r a l l t h e f i s h ! "
ok

, , dolphins.erl. , . ,
sh . , .

, Erlang. , ,
169

. , .

170

13

13.1

,
, ,
. , ,
,
.
.
, , kitchen.erl,
. :
.
, .
:
- module ( k i t c h e n ) .
- compile ( export_all ) .
f r i d g e 1 ( ) ->
receive
{From , { s t o r e , _Food} } ->
From ! { s e l f ( ) , ok } ,
fridge1 () ;
{From , { take , _Food} } ->
%% uh . . . .
From ! { s e l f ( ) , not_found } ,

171

fridge1 () ;
t e r m i n a t e ->
ok
end .

- . , ok, .
fridge1(),
, . , , ,
not_found. ,

.
, , . , , :
f r i d g e 2 ( F o o d L i s t ) ->
receive
{From , { s t o r e , Food} } ->
From ! { s e l f ( ) , ok } ,
f r i d g e 2 ( [ Food | F o o d L i s t ] ) ;
{From , { take , Food}} ->
c a s e l i s t s : member ( Food , F o o d L i s t ) o f
t r u e ->
From ! { s e l f ( ) , {ok , Food} } ,
f r i d g e 2 ( l i s t s : d e l e t e ( Food , F o o d L i s t ) ) ;
f a l s e ->
From ! { s e l f ( ) , not_found } ,
f r i d g e 2 ( FoodList )
end ;
t e r m i n a t e ->
ok
end .

, fridge2/1  FoodList. {From, {store, Food}} 


Food FoodList .
, .
. lists:member/2
Food FoodList . , (
FoodList ), not_found :
172

1> c ( k i t c h e n ) .
{ok , k i t c h e n }
2> Pid = spawn ( k i t c h e n , f r i d g e 2 , [ [ baking_soda ] ] ) .
<0.51.0 >
3> Pid ! { s e l f ( ) , { s t o r e , milk } } .
{ <0.33.0 > , { s t o r e , milk } }
4> f l u s h ( ) .
S h e l l g o t { <0.51.0 > , ok }
ok

.
, .
5> Pid ! { s e l f ( ) , { s t o r e , bacon } } .
{ <0.33.0 > , { s t o r e , bacon } }
6> Pid ! { s e l f ( ) , { take , bacon } } .
{ <0.33.0 > , { take , bacon } }
7> Pid ! { s e l f ( ) , { take , t u r k e y }} .
{ <0.33.0 > , { take , t u r k e y } }
8> f l u s h ( ) .
S h e l l g o t { <0.51.0 > , ok }
S h e l l g o t { <0.51.0 > , {ok , bacon } }
S h e l l g o t { <0.51.0 > , not_found }
ok

, , ( ), - , .
{<0.51.0>,not_found} .
13.2

, ,
, , . .
, ,
:
s t o r e ( Pid , Food ) ->
Pid ! { s e l f ( ) , { s t o r e , Food} } ,
receive

173

end .

{ Pid , Msg} -> Msg

t a k e ( Pid , Food ) ->


Pid ! { s e l f ( ) , { take , Food} } ,
receive
{ Pid , Msg} -> Msg
end .

9> c ( k i t c h e n ) .
{ok , k i t c h e n }
10> f ( ) .
ok
11> Pid = spawn ( k i t c h e n , f r i d g e 2 , [ [ baking_soda ] ] ) .
<0.73.0 >
12> k i t c h e n : s t o r e ( Pid , water ) .
ok
13> k i t c h e n : t a k e ( Pid , water ) .
{ok , water }
14> k i t c h e n : t a k e ( Pid , j u i c e ) .
not_found

, , self() - take store . pid ,


.
-.
. ,
. start/1 :
s t a r t ( F o o d L i s t ) ->
spawn ( ?MODULE, f r i d g e 2 , [ F o o d L i s t ] ) .

?MODULE  ,
. ,
, .

174

take/2 store/2 . - kitchen.


-,
( ), start/1 . spawn/3 , , , .
, .
:
15> f ( ) .
ok
16> c ( k i t c h e n ) .
{ok , k i t c h e n }
17> Pid = k i t c h e n : s t a r t ( [ rhubarb , dog , hotdog ] ) .
<0.84.0 >
18> k i t c h e n : t a k e ( Pid , dog ) .
{ok , dog }
19> k i t c h e n : t a k e ( Pid , dog ) .
not_found

! ,
!
13.3

-
pid(A,B,C) , 3 A, B
C pid. kitchen:take/2 pid:
20> k i t c h e n : t a k e ( p i d ( 0 , 2 5 0 , 0 ) , dog ) .

, .
take/2 . , , , :
1. ( ) -,
;
2.
;
175

3. 'ok';
4. .
:
1. ( )
;
2. ;
3. ,
, ;
4. .
, ,
. , . , ,
(
Erlang),
, . -,
.
,
, -
. , Erlang ,
receive .
receive
Match -> E x p r e s s i o n 1
a f t e r Delay ->
Expression2
end .

, ,
, receive after . after , Delay ( , ) ,
Match. Expression2.
176

store2/2 take2/2 ,
store/2 take/2 ,
3- :
s t o r e 2 ( Pid , Food ) ->
Pid ! { s e l f ( ) , { s t o r e , Food} } ,
receive
{ Pid , Msg} -> Msg
a f t e r 3000 ->
timeout
end .
t a k e 2 ( Pid , Food ) ->
Pid ! { s e l f ( ) , { take , Food} } ,
receive
{ Pid , Msg} -> Msg
a f t e r 3000 ->
timeout
end .

Ctrl-G, :
User s w i t c h command
- -> k
- -> s
- -> c
E s h e l l V5 . 7 . 5 ( a b o r t with ^G)
1> c ( k i t c h e n ) .
{ok , k i t c h e n }
2> k i t c h e n : t a k e 2 ( p i d ( 0 , 2 5 0 , 0 ) , dog ) .
timeout

.
: , after , innity . ( after
), , , .
, .
, , .
, time:sleep/1 , . (
177

multiproc.erl):
s l e e p (T) ->
receive
a f t e r T -> ok
end .

receive ,
.
T after .
, 0:
f l u s h ( ) ->
receive
_ -> f l u s h ( )
a f t e r 0 ->
ok
end .

Erlang , . . ush/0 ,
. ,
after 0 -> ok , .
13.4

(ushing) , :
i m p o r t a n t ( ) ->
receive
{ P r i o r i t y , Message } when P r i o r i t y > 10 ->
[ Message | i m p o r t a n t ( ) ]
a f t e r 0 ->
normal ( )
end .
normal ( ) ->
receive
{_, Message } ->
[ Message | normal ( ) ]
a f t e r 0 ->
[]

178

end .

. 10:
1> c ( m u l t i p r o c ) .
{ok , m u l t i p r o c }
2> s e l f ( ) ! { 1 5 , h i g h } , s e l f ( ) ! { 7 , low } , s e l f ( ) ! { 1 , low } ,
s e l f ( ) ! { 17 , high } .
{ 17 , high }
3> m u l t i p r o c : i m p o r t a n t ( ) .
[ high , high , low , low ]

after 0 ,
. 10, .
normal/0 .
, .
-
Erlang.
,
, . 12 , . ,
, .

receive ,
.
, 179

receive . receive , (
, ) .
,
(save queue) .
,
,
.

,
.
, , (selective receives (selective
receives)). , : ,
,
( ).
, . ,
367- , 366  ,
. 367- , 366- .
,
, 367- , 366
. .
Erlang. , 180

, ,
.

, , , ?
? ?
, ? , , , ?
.
, , Erlang
, .
:
receive
P a t t e r n 1 -> E x p r e s s i o n 1 ;
P a t t e r n 2 -> E x p r e s s i o n 2 ;
P a t t e r n 3 -> E x p r e s s i o n 3 ;
...
PatternN -> ExpressionN ;
Unexpected ->
i o : format ( " unexpected message ~p~n" , [ Unexpected ] )
end .

,
. Unexpected
,
. ,
- ,
.
, ,
, - ,
.
, ,
min- gb_trees
(,  ).
, .

, . 181

,
. ,
.
: R14A, Erlang
.
. optimized/1
multiproc.erl.
,
( make_ref() ) . ,
.
,
,
,
.
,
. Erlang
, .
, . .
, .

182

14

14.1

 , . ,
, , (. 9 ),
.
,
, . , , ,
, , ,
- .

. .
, Erlang
link/1, Pid.
, Pid.
unlink/1.
, , .
(: ), .
linkmon.erl:
myproc ( ) ->
timer : s l e e p (5000) ,
e x i t ( reason ) .

183

( spawn ), ,
'reason',
.
1> c ( linkmon ) .
{ok , linkmon }
2> spawn ( fun linkmon : myproc / 0 ) .
<0.52.0 >
3> l i n k ( spawn ( fun linkmon : myproc / 0 ) ) .
true
** e x c e p t i o n e r r o r : r e a s o n

{'EXIT', B, Reason} try . . . catch . , .


, , , :
c h a i n ( 0 ) ->
receive
_ -> ok
a f t e r 2000 ->
e x i t ( " chain d i e s here " )
end ;
c h a i n (N) ->
Pid = spawn ( fun ( ) -> c h a i n (N- 1 ) end ) ,
l i n k ( Pid ) ,
receive
_ -> ok
end .

184

N, N
. N-1 , .
spawn(?MODULE, chain, [N-1]) .
,
,
:
4> c ( linkmon ) .
{ok , linkmon }
5> l i n k ( spawn ( linkmon , chain , [ 3 ] ) ) .
true
** e x c e p t i o n e r r o r : " c h a i n d i e s h e r e "

,
.
:
[ shell
[ shell
[ shell
[ shell
[ shell
* dead ,
[ shell

]
]
]
]
]

== [ 3 ] == [ 2 ] == [ 1 ] == [ 0 ]
== [ 3 ] == [ 2 ] == [ 1 ] == * dead *
== [ 3 ] == [ 2 ] == * dead *
== [ 3 ] == * dead *
== * dead *
e r r o r message shown*
] <-- r e s t a r t e d

, linkmon:chain(0) ,
, - . . ,
.
: - , exit/2. : exit(Pid, Reason) .
, .

: . link/1 15

,
,
unlink/1 .
, link(spawn(Function)) link(spawn(M,F,A))
.
, .
185

spawn_link/1-3. , spawn/1-3 ,
, link/1 ,
(
,
, ). . , .
14.2

. , ,  .  ,
, .
,
.
.
.
, - ,
. ,
( ), , (system processes). ,
, ,
.
process_ag(trap_exit, true) .
, .
. chain,
:
1> p r o c e s s _ f l a g ( t r a p _ e x i t , t r u e ) .
true
2> spawn_link ( fun ( ) -> linkmon : c h a i n ( 3 ) end ) .
<0.49.0 >
3> r e c e i v e X -> X end .
{ 'EXIT ' , <0.49.0 > , " c h a i n d i e s h e r e " }

186

! . .
:
[
[
[
[
[
[

shell
shell
shell
shell
shell
shell

]
]
]
]
]
]

== [ 3 ] == [ 2 ] == [ 1 ] == [ 0 ]
== [ 3 ] == [ 2 ] == [ 1 ] == * dead *
== [ 3 ] == [ 2 ] == * dead *
== [ 3 ] == * dead *
< - - { 'EXIT , Pid , " c h a i n d i e s h e r e " } - - * dead *
<-- s t i l l a l i v e !

, .
,
,  ,
, .
,
.
,
9 ,
,
. ,
. ,
, (exits)
:
: spawn_link(fun() -> ok end)
, : - nothing : {'EXIT', <0.61.0>, normal}
, . ,
catch_exit(normal) ,
, PID.
: spawn_link(fun() -> exit(reason) end)
, : ** exception exit: reason
: {'EXIT', <0.55.0>, reason}
, .
(exit) , .
, .
: spawn_link(fun() -> exit(normal) end)
, : - nothing 187

: {'EXIT', <0.58.0>, normal}

.
,
.
.
: spawn_link(fun() -> 1/0 end)
, : Error in process <0.44.0>
with exit value: {badarith, [{erlang, '/', [1,0]}]}
: {'EXIT', <0.52.0>, {badarith, [{erlang, '/',
[1,0]}]}}
( {badarith, Reason} ) try . . . catch
, 'EXIT'.
exit(reason) , c ,
.
: spawn_link(fun() -> erlang:error(reason) end)
, : Error in process <0.47.0>
with exit value: {reason, [{erlang, apply, 2}]}
: {'EXIT', <0.74.0>, {reason, [{erlang, apply,
2}]}}
1/0 . ,
erlang:error/1
.
: spawn_link(fun() -> throw(rocks) end)
, : Error in process <0.51.0>
with exit value: {{nocatch, rocks}, [{erlang, apply, 2}]}
: {'EXIT', <0.79.0>, {{nocatch, rocks}, [{erlang,
apply, 2}]}}
(throw) try. . . catch
(error), EXIT.
exit, .
- .
, , , .  .
-  , .
188

exit/2 .  - ,
Erlang. , . ,
:
: exit(self(), normal)
, : ** exception exit: normal
: {'EXIT', <0.31.0>, normal}
exit(self(), normal) (exits),
exit(normal) .
,
(links) (foreign)
.
: exit(spawn_link(fun() -> timer:sleep(50000) end), normal)
, : - nothing : - nothing , exit(Pid, normal) . ,
normal .
: exit(spawn_link(fun() -> timer:sleep(50000) end), reason)
, : ** exception exit: reason
: {'EXIT', <0.52.0>, reason}
(foreign) reason. ,
exit(reason) .
: exit(spawn_link(fun() -> timer:sleep(50000) end), kill)
, : ** exception exit: killed
: {'EXIT', <0.58.0>, killed}
, . killed
kill. , kill  .
.
: exit(self(), kill)

, : ** exception exit: killed


: ** exception exit: killed
, -. . .
189

: spawn_link(fun() -> exit(kill) end)


, : ** exception exit: killed
: {'EXIT', <0.67.0>, kill}
- . - exit(kill) , (exits)
killed .
, .
,
,
. , ,
(exits),
. kill , . ,
, , .
kill , .
kill
, killed . ,
, , kill ,
, , ,
. .
,
exit(kill) killed ( , ), ,
kill .
, . . - .
, ,
. ,

Erlang.

190

14.3

, . , .
, .
, .
.
, ,
:
;
(stack).
, -
, ,
.
,  (stacking) . ,
,
,
.
, .
, , .
, -
..
, . ,
.
, 2- 3- , , ? .
, , , ,
, , . . ,
, ,

191

. . , ,
.
? .
erlang:monitor/2,
process,  pid :
1> e r l a n g : monitor ( p r o c e s s , spawn ( fun ( ) -> t i m e r : s l e e p ( 5 0 0 ) end ) ) .
#Ref <0.0.0.77 >
2> f l u s h ( ) .
S h e l l g o t { 'DOWN' ,#Ref < 0 . 0 . 0 . 7 7 > , p r o c e s s , <0.63.0 > , normal }
ok

, ,
{'DOWN', MonitorReference, process, Pid, Reason} .
. ,
, .
. ,
,
 spawn_monitor/1-3:
3> { Pid , Ref } = spawn_monitor ( fun ( ) -> r e c e i v e _ -> e x i t ( boom )
end end ) .
{ <0.73.0 > ,# Ref <0.0.0.100 > }
4> e r l a n g : demonitor ( Ref ) .
true
5> Pid ! d i e .
die
6> f l u s h ( ) .
ok

, . demonitor/2, .
.
: info ush :
7> f ( ) .
ok
8> { Pid , Ref } = spawn_monitor ( fun ( ) -> r e c e i v e _ -> e x i t ( boom )
end end ) .
{ <0.35.0 > ,# Ref <0.0.0.35 > }
9> Pid ! d i e .
die
10> e r l a n g : demonitor ( Ref , [ f l u s h , i n f o ] ) .

192

false
11> f l u s h ( ) .
ok

info , . 10
false . ush DOWN , , , . ush()
.
14.4

,
.
linkmon.erl:
s t a r t _ c r i t i c ( ) ->
spawn ( ?MODULE, c r i t i c , [ ] ) .
j u d g e ( Pid , Band , Album ) ->
Pid ! { s e l f ( ) , {Band , Album} } ,
receive
{ Pid , C r i t i c i s m } -> C r i t i c i s m
a f t e r 2000 ->
timeout
end .
c r i t i c ( ) ->
receive
{From , { "Rage A g a i n s t t h e Turing Machine " , " Unit T e s t i f y "
} } ->
From ! { s e l f ( ) , "They a r e g r e a t ! " } ;
{From , { " System o f a Downtime" , "Memoize" } } ->
From ! { s e l f ( ) , "They ' r e not Johnny Crash but they ' r e
good . " } ;
{From , { " Johnny Crash " , "The Token Ring o f F i r e " } } ->
From ! { s e l f ( ) , " Simply i n c r e d i b l e . " } ;
{From , {_Band , _Album} } ->
From ! { s e l f ( ) , "They a r e t e r r i b l e ! " }
end ,
c r i t i c () .

, , . , . 
.
193

1> c ( linkmon ) .
{ok , linkmon }
2> C r i t i c = linkmon : s t a r t _ c r i t i c ( ) .
<0.47.0 >
3> linkmon : j u d g e ( C r i t i c , " G e n e s i s " , "The Lambda L i e s Down on
Broadway" ) .
"They a r e t e r r i b l e ! "

- ( - ), :
4> e x i t ( C r i t i c , s o l a r _ s t o r m ) .
true
5> linkmon : j u d g e ( C r i t i c , " G e n e s i s " , "A t r i c k o f t h e T a i l
Recursion " ) .
timeout

.
. , (supervisor),
 , :
s t a r t _ c r i t i c 2 ( ) ->
spawn ( ?MODULE, r e s t a r t e r , [ ] ) .
r e s t a r t e r ( ) ->
process_flag ( trap_exit , true ) ,
Pid = spawn_link ( ?MODULE, c r i t i c , [ ] ) ,
receive
{ 'EXIT ' , Pid , normal } -> % not a c r a s h
ok ;
{ 'EXIT ' , Pid , shutdown } -> % manual t e r m i n a t i o n , not a
crash
ok ;
{ 'EXIT ' , Pid , _} ->
restarter ()
end .

. , -, -
, restarter/0 . , {'EXIT', Pid, shutdown}
,
- .
:
Pid .
194

, .
Erlang .
pid .
Pid. erlang:register/2. , .
unregister/1.
registered/0, regs() . restarter/0 :
r e s t a r t e r ( ) ->
process_flag ( trap_exit , true ) ,
Pid = spawn_link ( ?MODULE, c r i t i c , [ ] ) ,
r e g i s t e r ( c r i t i c , Pid ) ,
receive
{ 'EXIT ' , Pid , normal } -> % not a c r a s h
ok ;
{ 'EXIT ' , Pid , shutdown } -> % manual t e r m i n a t i o n , not a
crash
ok ;
{ 'EXIT ' , Pid , _} ->
restarter ()
end .

, Pid , register/2
critic.
Pid. :
j u d g e 2 ( Band , Album ) ->
c r i t i c ! { s e l f ( ) , {Band , Album} } ,
Pid = w h e r e i s ( c r i t i c ) ,
receive
{ Pid , C r i t i c i s m } -> C r i t i c i s m
a f t e r 2000 ->
timeout
end .

Pid = whereis(critic) -, receive . , ,


( , , 500
!) . , pid
. ,
195

:
1. critic ! Message
2. critic
3. critic
4. critic
5. whereis
6. critic
7.
:
1. critic ! Message

2. critic
3. critic
4. critic
5. critic
6. whereis pid
7.
, ,
.
critic .
. , critic

.
.
race condition.
, .

, , , ,
,
.

196

: , , Erlang

(race conditions)
(deadlocks), , ,
. ,
,
.

.

,
( ),
..
, , ,
. ,
,
( make_ref() .
critic/0 critic2/0 , judge/3 judge2/2 :
j u d g e 2 ( Band , Album ) ->
Ref = make_ref ( ) ,
c r i t i c ! { s e l f ( ) , Ref , {Band , Album} } ,
receive
{ Ref , C r i t i c i s m } -> C r i t i c i s m
a f t e r 2000 ->
timeout
end .
c r i t i c 2 ( ) ->
receive
{From , Ref , { "Rage A g a i n s t t h e Turing Machine " , " Unit
T e s t i f y " } } ->
From ! { Ref , "They a r e g r e a t ! " } ;
{From , Ref , { " System o f a Downtime" , "Memoize" } } ->
From ! { Ref , "They ' r e not Johnny Crash but they ' r e
good . "} ;
{From , Ref , { " Johnny Crash " , "The Token Ring o f F i r e " } }
->
From ! { Ref , " Simply i n c r e d i b l e . " } ;
{From , Ref , {_Band , _Album} } ->
From ! { Ref , "They a r e t e r r i b l e ! " }
end ,
c r i t i c 2 () .

restarter/0 , critic/0
critic2/0 . .
197

. ,
, ,
, ,
. , ,
pid:
6> c ( linkmon ) .
{ok , linkmon }
7> linkmon : s t a r t _ c r i t i c 2 ( ) .
<0.55.0 >
8> linkmon : j u d g e 2 ( "The Doors " , " L i g h t my F i r e w a l l " ) .
"They a r e t e r r i b l e ! "
9> e x i t ( w h e r e i s ( c r i t i c ) , k i l l ) .
true
10> linkmon : j u d g e 2 ( "Rage A g a i n s t t h e Turing Machine " , " Unit
Testify ") .
"They a r e g r e a t ! "

, ,
. , .
linkmon:judge/2
, ! bad
argument, , ,
, .
: ,
( ).
.
,
VM,
.
,
, VM
, .
,
,
.

Erlang .

198

15

(concurrent)
, , .
, , ,

: ,
, ..
-
.

(oncurrent) Erlang.

. ,

.
.
, , , , ,
. ,
, . ,
(
). ,
- .
15.1

- , .
: . , ,  .
199

. ?
? ?
, ?
:
, .
.
:
.
( , ),
.
, .
.
.
, , .
, ,
, ,
, ,
.
,
.
,

(, , ,
-,
(instant messaging), ).
:

, x, y, z .
:
200

15.1.1

.
, ,
.
(
x, y, z).
,
- .
.
.
15.1.2


. ,
,
.
,
( , -,
, ..).
.
.
( ).
.
15.1.3

x, y z

, (
, ).
.
.

201

, (IM, ..,
) ,
,
. , ,
.
, :

, .
.
, .
,
. ,
. ,
, .
, , ,
timer:send_after/2-3,
.

202

15.2

,
,
, .
:

,
. ,
, .
(link), ,
,
,
.
, ,
(exits) .
:

.
ok , ,
- (, TimeOut
.)
:

203

,
:

:
, :

,
. , - ,
.
,
.
, ,
(links)
. , ,

.
, . ,
( ).
- ,
:

204

, ,
:

. - ,
:

.
, , .
,
. -
.
15.3


,
Erlang. :
ebin/
include/
priv/
src/
ebin/
.
include/ .hrl ,
; .hrl ,
(private),
src/ . priv/ ,
205

Erlang.
.
.  src/ ,
.erl .

Erlang.
conf/ , doc/
lib/  ,
. Erlang-,
, , ,
, ,
(standard practices) OTP.
15.4

src/ event.erl,
x, y z, .
, .
,
.
, ,
. ,
,
. ?  ..
{Pid, Ref, Message} , Pid  Ref 
, ,
.
, ,
.
. , event.erl
loop/1 ,
, :
l o o p ( S t a t e ) ->
receive
{ S e r v e r , Ref , c a n c e l } ->
...
a f t e r Delay ->
...
end .

206

-,
, .
State.
- ( ) (
{done, Id} .) ,
pid.

. state :
- module ( e v e n t ) .
- compile ( export_all ) .
- record ( state , { server ,
name="" ,
to_go=0} ) .

,
:
l o o p ( S = #s t a t e { s e r v e r=S e r v e r } ) ->
receive
{ S e r v e r , Ref , c a n c e l } ->
S e r v e r ! { Ref , ok }
a f t e r S#s t a t e . to_go *1000 ->
S e r v e r ! { done , S#s t a t e . name}
end .

to_go
.

! Server
receive,
. ,
11.2  ! S#state.server
element(2, S) ,
.
S#state.to_go , after ,
,
.
:
6> c ( e v e n t ) .
{ok , e v e n t }
7> r r ( event , s t a t e ) .
[ state ]
8> spawn ( event , loop , [#s t a t e { s e r v e r= s e l f ( ) , name=" t e s t " , to_go=5
}]).

207

<0.60.0 >
9> f l u s h ( ) .
ok
10> f l u s h ( ) .
S h e l l g o t { done , " t e s t " }
ok
11> Pid = spawn ( event , loop , [#s t a t e { s e r v e r= s e l f ( ) , name=" t e s t " ,
to_go=500} ] ) .
<0.64.0 >
12> ReplyRef = make_ref ( ) .
#Ref <0.0.0.210 >
13> Pid ! { s e l f ( ) , ReplyRef , c a n c e l } .
{ <0.50.0 > ,# Ref < 0 . 0 . 0 . 2 1 0 > , c a n c e l }
14> f l u s h ( ) .
S h e l l g o t {#Ref < 0 . 0 . 0 . 2 1 0 > , ok }
ok

.
(record) rr(Mod) .
,
( self() ). 5 .
9- 3 , 10-  6 .
, {done, "test"} .
(
c 500 ). , ,
, .
, ok
, -
.
, done  .
, done - ( ,
receive), .
. ,
?
15> spawn ( event , loop , [#s t a t e { s e r v e r= s e l f ( ) , name=" t e s t " , to_go
=365*24*60*60 } ] ) .
<0.69.0 >
16>
=ERROR REPORT==== DD-MM-YYYY: : HH:mm: SS ===
E r r o r i n p r o c e s s <0.69.0 > with e x i t v a l u e : { timeout_value , [ { event
, loop , 1 } ] }

. , .
- Erlang
208

50 ( ). ,
, :
1. , ,
.
2. , Erlang
.
, .
3. , -, ;
.
,
- .
loop/1 . ,
49 (
50 ),
.
:
%% Because Erl ang i s l i m i t e d t o about 49 days ( 4 9 * 2 4 * 6 0 * 6 0 * 1 0 0 0 )
in
%% m i l l i s e c o n d s , t h e f o l l o w i n g f u n c t i o n i s used
n o r m a l i z e (N) ->
L imi t = 4 9 * 2 4 * 6 0 * 6 0 ,
[N rem Li mi t | l i s t s : d u p l i c a t e (N d i v Limit , L imi t ) ] .

lists:duplicate/2
,
( [a,a,a] = lists:duplicate(3, a) ).
normalize/1 98*24*60*60+4 , [4,4233600,423360] .
, loop/2
:
%% Loop u s e s a l i s t f o r t i m e s i n o r d e r t o go around t h e ~49 days
limit
%% on t i m e o u t s .
l o o p ( S = #s t a t e { s e r v e r=S e r v e r , to_go=[ T | Next ] } ) ->
receive
{ S e r v e r , Ref , c a n c e l } ->
S e r v e r ! { Ref , ok }
a f t e r T*1000 ->
i f Next =:= [ ] ->
S e r v e r ! { done , S#s t a t e . name} ;
Next =/= [ ] ->

209

end .

end

l o o p ( S#s t a t e { to_go=Next } )

, ,
-
. :
to_go
, . ,
, . ,
- , .
,
.
, - - event:normalize(N) ,
,
, .
 init ,
, .
,
start start_link :
s t a r t ( EventName , Delay ) ->
spawn ( ?MODULE, i n i t , [ s e l f ( ) , EventName , Delay ] ) .
s t a r t _ l i n k ( EventName , Delay ) ->
spawn_link ( ?MODULE, i n i t , [ s e l f ( ) , EventName , Delay ] ) .
%%% Event ' s i n n a r d s
i n i t ( S e r v e r , EventName , Delay ) ->
l o o p (# s t a t e { s e r v e r=S e r v e r ,
name=EventName ,
to_go=n o r m a l i z e ( Delay ) } ) .

.
, ,
,
:
c a n c e l ( Pid ) ->
%% Monitor i n c a s e t h e p r o c e s s i s a l r e a d y dead
Ref = e r l a n g : monitor ( p r o c e s s , Pid ) ,
Pid ! { s e l f ( ) , Ref , c a n c e l } ,
receive
{ Ref , ok } ->
e r l a n g : demonitor ( Ref , [ f l u s h ] ) ,

210

end .

ok ;
{ 'DOWN' , Ref , p r o c e s s , Pid , _Reason} ->
ok

!
. ,
, ok , .
, , : ,
. ,
ush , DOWN ,
.
:
17> c ( e v e n t ) .
{ok , e v e n t }
18> f ( ) .
ok
19> e v e n t : s t a r t ( " Event " , 0 ) .
<0.103.0 >
20> f l u s h ( ) .
S h e l l g o t { done , " Event " }
ok
21> Pid = e v e n t : s t a r t ( " Event " , 5 0 0 ) .
<0.106.0 >
22> e v e n t : c a n c e l ( Pid ) .
ok

! ,

.
, datetime Erlang ( {{Year, Month, Day}, {Hour, Minute, Second}} ).
,
:
time_to_go ( TimeOut={ {_, _,_} , {_, _,_} } ) ->
Now = c a l e n d a r : l o c a l _ t i m e ( ) ,
ToGo = c a l e n d a r : da t e t im e _ to _ g r eg o r ia n _ s e co n d s ( TimeOut ) c a l e n d a r : d a t e ti m e _ to _ g r eg o r ia n _ s ec o n d s (Now) ,
S e c s = i f ToGo > 0 -> ToGo ;
ToGo =< 0 -> 0
end ,
normalize ( Secs ) .

, .
,
, .
211

, 0,
. init,
normalize/1 . Delay ,
, DateTime, , :
i n i t ( S e r v e r , EventName , DateTime ) ->
l o o p (# s t a t e { s e r v e r=S e r v e r ,
name=EventName ,
to_go=time_to_go ( DateTime ) } ) .

, . ,
, (-) /
, , .
15.5

. ,
:
- module ( e v s e r v ) .
- compile ( export_all ) .
l o o p ( S t a t e ) ->
receive
{ Pid , MsgRef , { s u b s c r i b e , C l i e n t } } ->
...
{ Pid , MsgRef , {add , Name , D e s c r i p t i o n , TimeOut} } ->
...
{ Pid , MsgRef , { c a n c e l , Name} } ->
...
{ done , Name} ->
...
shutdown ->
...
{ 'DOWN' , Ref , p r o c e s s , _Pid , _Reason} ->
...
code_change ->
...
Unknown ->
i o : format ( "Unknown message : ~p~n" , [ Unknown ] ) ,
loop ( State )
end .

, ,
, {Pid, Ref, Message} ,
. :
212

-.
, : ,
, {done, Name} ,
{done, Name, Description} . ,
, -
. ,
:
- record ( state , { events ,
%% l i s t o f #e v e n t { } r e c o r d s
c l i e n t s } ) . %% l i s t o f Pids
- r e c o r d ( event , {name=" " ,
d e s c r i p t i o n=" " ,
pid ,
t i m e o u t={ { 1 9 7 0 , 1 , 1 } , { 0 , 0 , 0 } } } ) .

(record
denition):
l o o p ( S = #s t a t e { } ) ->
receive
...
end .


(orddicts). ,
, .
11.3 , , orddict-
.
init :
i n i t ( ) ->
%% Loading e v e n t s from a s t a t i c f i l e c o u l d be done h e r e .
%% You would need t o p a s s an argument t o i n i t t e l l i n g where
the
%% r e s o u r c e t o f i n d t h e e v e n t s i s . Then l o a d i t from h e r e .
%% Another o p t i o n i s t o j u s t p a s s t h e e v e n t s s t r a i g h t t o t h e
server
%% through t h i s f u n c t i o n .
l o o p (# s t a t e { e v e n t s=o r d d i c t : new ( ) ,
c l i e n t s=o r d d i c t : new ( ) } ) .

.
.
. ,
.
, (monitor)
213

. ,

. , :
{ Pid , MsgRef , { s u b s c r i b e , C l i e n t } } ->
Ref = e r l a n g : monitor ( p r o c e s s , C l i e n t ) ,
NewClients = o r d d i c t : s t o r e ( Ref , C l i e n t , S#s t a t e . c l i e n t s ) ,
Pid ! {MsgRef , ok } ,
l o o p ( S#s t a t e { c l i e n t s=NewClients } ) ;

loop/1
:
orddict-,
Ref.
:
ID ,
EXIT ,
(
orddict-).
,
,
. ,
.

(timestamps).
{{Year,Month,Day}, {Hour,Minute,seconds}} ,
, , , ,
29 ,
.
, (
: 5 , 1 75 ).
.
, ,
calendar:valid_date/1. ,
. ,

 :
, , {H,M,S}
. ,
,
:
v a l i d _ d a t e t i m e ( { Date , Time} ) ->
try

214

c a l e n d a r : v a l i d _ d a t e ( Date ) a n d a l s o v a l i d _ t i m e ( Time )
catch
e r r o r : f u n c t i o n _ c l a u s e -> %% not i n { {Y,M,D} , {H, Min , S} }
format
false
end ;
v a l i d _ d a t e t i m e (_) ->
false .
v a l i d _ t i m e ( {H,M, S} ) -> v a l i d _ t i m e (H,M, S ) .
v a l i d _ t i m e (H,M, S ) when H >= 0 , H < 2 4 ,
M >= 0 , M < 6 0 ,
S >= 0 , S < 60 -> t r u e ;
v a l i d _ t i m e (_, _,_) -> f a l s e .

valid_datetime/1
, :
{ Pid , MsgRef , {add , Name , D e s c r i p t i o n , TimeOut} } ->
c a s e v a l i d _ d a t e t i m e ( TimeOut ) o f
t r u e ->
EventPid = e v e n t : s t a r t _ l i n k (Name , TimeOut ) ,
NewEvents = o r d d i c t : s t o r e (Name ,
#e v e n t {name=Name ,
d e s c r i p t i o n=D e s c r i p t i o n ,
p i d=EventPid ,
t i m e o u t=TimeOut} ,
S#s t a t e . e v e n t s ) ,
Pid ! {MsgRef , ok } ,
l o o p ( S#s t a t e { e v e n t s=NewEvents} ) ;
f a l s e ->
Pid ! {MsgRef , { e r r o r , bad_timeout } } ,
loop (S)
end ;

, -,
. -
, ,

. , -
, (,
!)
, ,
.
, . ,
(record) .
215

, event:cancel/1 ,
ok. ,
,  ,
, .
{ Pid , MsgRef , { c a n c e l , Name} } ->
Events = c a s e o r d d i c t : f i n d (Name , S#s t a t e . e v e n t s ) o f
{ok , E} ->
e v e n t : c a n c e l (E#e v e n t . p i d ) ,
o r d d i c t : e r a s e (Name , S#s t a t e . e v e n t s ) ;
e r r o r ->
S#s t a t e . e v e n t s
end ,
Pid ! {MsgRef , ok } ,
l o o p ( S#s t a t e { e v e n t s=Events } ) ;

, . ,
.
,
. :
( ), (timing out)
. {done, Name} :
{ done , Name} ->
c a s e o r d d i c t : f i n d (Name , S#s t a t e . e v e n t s ) o f
{ok , E} ->
s e n d _ t o _ c l i e n t s ( { done , E#e v e n t . name , E#e v e n t .
description } ,
S#s t a t e . c l i e n t s ) ,
NewEvents = o r d d i c t : e r a s e (Name , S#s t a t e . e v e n t s ) ,
l o o p ( S#s t a t e { e v e n t s=NewEvents} ) ;
e r r o r ->
%% This may happen i f we c a n c e l an e v e n t and
%% i t f i r e s a t t h e same time
loop (S)
end ;

send_to_clients/2 ,
, :
s e n d _ t o _ c l i e n t s ( Msg , C l i e n t D i c t ) ->
o r d d i c t : map( fun ( _Ref , Pid ) -> Pid ! Msg end , C l i e n t D i c t ) .

.
, :
, , .. :
shutdown ->

216

e x i t ( shutdown ) ;
{ 'DOWN' , Ref , p r o c e s s , _Pid , _Reason} ->
l o o p ( S#s t a t e { c l i e n t s=o r d d i c t : e r a s e ( Ref , S#s t a t e . c l i e n t s ) } ) ;
code_change ->
?MODULE: l o o p ( S ) ;
Unknown ->
i o : format ( "Unknown message : ~p~n" , [ Unknown ] ) ,
loop (S)

( shutdown ) .
,
. ,
.
/,
add , cancel done .
init ,
- .
, DOWN ,
. , ,
,
.

io:format/2 . ,
, .
.
,
.
15.6

Erlang ,
.
, ETS ( ,
 VM.)
,
.
c(Module) , l(Module)

.
, Erlang
(local) (external) .
, . :
217

Atom(Args) . (external) , ,
, Module:Function(Args) .
,
,
.
, . ,
, ,
.

, / Erlang
,
,
.
: ,
,
. ,
-, ,
(upgrade).
, ,
.
, ,

.
, ,
, MyModule:Upgrade(CurrentState) ,
,
.
OTP, . -
,
218

code_change ,
.
, .
, :
- module ( h o t l o a d ) .
- e x p o r t ( [ s e r v e r / 1 , upgrade /1 ] ) .
s e r v e r ( S t a t e ) ->
receive
update ->
NewState = ?MODULE: upgrade ( S t a t e ) ,
?MODULE: s e r v e r ( NewState ) ; %% l o o p i n t h e new v e r s i o n
o f t h e module
SomeMessage ->
%% do something h e r e
s e r v e r ( S t a t e ) %% s t a y i n t h e same v e r s i o n no matter
what .
end .
upgrade ( O l d S t a t e ) ->
%% t r a n s f o r m and r e t u r n t h e s t a t e h e r e .

, ?MODULE:loop(S)
.
15.7

! ,
,
. evserv :
s t a r t ( ) ->
r e g i s t e r ( ?MODULE, Pid=spawn ( ?MODULE, i n i t , [ ] ) ) ,
Pid .
s t a r t _ l i n k ( ) ->
r e g i s t e r ( ?MODULE, Pid=spawn_link ( ?MODULE, i n i t , [ ] ) ) ,
Pid .
t e r m i n a t e ( ) ->
?MODULE ! shutdown .

,
.
,
,
219

, gproc.
.
,
.
, ,
, . ,
, DOWN ,
, .
s u b s c r i b e ( Pid ) ->
Ref = e r l a n g : monitor ( p r o c e s s , w h e r e i s ( ?MODULE) ) ,
?MODULE ! { s e l f ( ) , Ref , { s u b s c r i b e , Pid } } ,
receive
{ Ref , ok } ->
{ok , Ref } ;
{ 'DOWN' , Ref , p r o c e s s , _Pid , Reason } ->
{ e r r o r , Reason }
a f t e r 5000 ->
{ error , timeout }
end .

:
add_event (Name , D e s c r i p t i o n , TimeOut ) ->
Ref = make_ref ( ) ,
?MODULE ! { s e l f ( ) , Ref , {add , Name , D e s c r i p t i o n , TimeOut} } ,
receive
{ Ref , Msg} -> Msg
a f t e r 5000 ->
{ error , timeout }
end .

,
{error, bad_timeout} -, erlang:error(bad_timeout) . ,
: -
, .
, :
add_event2 (Name , D e s c r i p t i o n , TimeOut ) ->
Ref = make_ref ( ) ,
?MODULE ! { s e l f ( ) , Ref , {add , Name , D e s c r i p t i o n , TimeOut} } ,
receive
{ Ref , { e r r o r , Reason } } -> e r l a n g : e r r o r ( Reason ) ;
{ Ref , Msg} -> Msg
a f t e r 5000 ->
{ error , timeout }
end .

220

. , ,
:
c a n c e l (Name) ->
Ref = make_ref ( ) ,
?MODULE ! { s e l f ( ) , Ref , { c a n c e l , Name} } ,
receive
{ Ref , ok } -> ok
a f t e r 5000 ->
{ error , timeout }
end .

, ,
, ,
.
,
, :
l i s t e n ( Delay ) ->
receive
M = { done , _Name, _ D e s c r i p t i o n } ->
[M | l i s t e n ( 0 ) ]
a f t e r Delay *1000 ->
[]
end .

15.8


. ,
Erlang- makele .
Emakele . Erlang
Erlang
.beam :
{ ' s r c /* ' , [ debug_info ,
{ i , " s r c "} ,
{ i , " i n c l u d e "} ,
{ outdir , " ebin "} ] } .

:
debug_info ( ),
src/ include/ ,
ebin/ .
221


erl -make , ,
ebin/ .
Erlang erl -pa ebin/ .
-pa <directory>
Erlang,
.

make:all([load]) .
Emakele
,
( ) .
(
DateTime ,
):
1> e v s e r v : s t a r t ( ) .
<0.34.0 >
2> e v s e r v : s u b s c r i b e ( s e l f ( ) ) .
{ok ,#Ref <0.0.0.31 > }
3> e v s e r v : add_event ( "Hey t h e r e " , " t e s t " , FutureDateTime ) .
ok
4> e v s e r v : l i s t e n ( 5 ) .
[]
5> e v s e r v : c a n c e l ( "Hey t h e r e " ) .
ok
6> e v s e r v : add_event ( "Hey t h e r e 2 " , " t e s t " , NextMinuteDateTime ) .
ok
7> e v s e r v : l i s t e n ( 2 0 0 0 ) .
[ { done , "Hey t h e r e 2 " , " t e s t " } ]

.
,
.
15.9

, ,
''(restarter), ,
14.4 . sup.erl,
:
- module ( sup ) .
- e x p o r t ( [ s t a r t / 2 , s t a r t _ l i n k / 2 , i n i t / 1 , l o o p /1 ] ) .

222

s t a r t (Mod, Args ) ->


spawn ( ?MODULE, i n i t , [ {Mod, Args } ] ) .
s t a r t _ l i n k (Mod, Args ) ->
spawn_link ( ?MODULE, i n i t , [ {Mod, Args } ] ) .
i n i t ( {Mod, Args } ) ->
process_flag ( trap_exit , true ) ,
l o o p ( {Mod, s t a r t _ l i n k , Args } ) .
l o o p ( {M, F ,A} ) ->
Pid = apply (M, F ,A) ,
receive
{ 'EXIT ' , _From , shutdown } ->
e x i t ( shutdown ) ; % w i l l k i l l t h e c h i l d t o o
{ 'EXIT ' , Pid , Reason } ->
i o : format ( " P r o c e s s ~p e x i t e d f o r r e a s o n ~p~n" , [ Pid ,
Reason ] ) ,
l o o p ( {M, F ,A} )
end .

- '',
,
start_link . , ,
,
, .
:
1> c ( e v s e r v ) , c ( sup ) .
{ok , sup }
2> SupPid = sup : s t a r t ( e v s e r v , [ ] ) .
<0.43.0 >
3> w h e r e i s ( e v s e r v ) .
<0.44.0 >
4> e x i t ( w h e r e i s ( e v s e r v ) , d i e ) .
true
P r o c e s s <0.44.0 > e x i t e d f o r r e a s o n d i e
5> e x i t ( w h e r e i s ( e v s e r v ) , d i e ) .
P r o c e s s <0.48.0 > e x i t e d f o r r e a s o n d i e
true
6> e x i t ( SupPid , shutdown ) .
true
7> w h e r e i s ( e v s e r v ) .
undefined

,
.
223

OTP.
, (supervision trees).
,
.
, .
15.10

( )

- , Erlang
( ),

.

user ,
.
user ,
Erlang.

code:clash/0.
:
.
- reminder_evserv ,
reminder_sup reminder_event .
,
.
,
.
,
, ..
,
, ,
..
, , ,
(concurrent) Erlang-. , ,
,
: , , , - (
), ..
224

, , .

.
evserv.erl ,
-
Erlang, , -
.
,
OTP.
,
. Erlang
.
,
Erlang.

225

16
OTP?
16.1

OTP ,
, (
,
,
). ,
Erlang
(concurrency) ,

, OTP
.

, (concurrent)
, : (links), ,
, , (trapping exits), ..
,
. , (race conditions),
, ,
.
, .
,
, .
, , ,
226

. OTP ,
,
.
Erlang.
OTP ,
. ,
Erlang
OTP, ,
, .
16.2

,
,
.
, ,
, ,
..
,
(concurrent) , ,
.

, OTP,
.
, ,
(, , ).
,
,
, .
,
. ,
. ,
227

, ,
.
, , .


,
.

OTP (OTP framework's behaviours), .
16.3

, ,
. 15 ,
, -.
, ,
.
,
.

%%%%% Naive v e r s i o n
- module ( k i t t y _ s e r v e r ) .

228

- e x p o r t ( [ s t a r t _ l i n k / 0 , o r d e r _ c a t / 4 , r e t u r n _ c a t / 2 , c l o s e _ s h o p /1 ] ) .
- r e c o r d ( cat , {name , c o l o r=green , d e s c r i p t i o n } ) .
%%% C l i e n t API
s t a r t _ l i n k ( ) -> spawn_link ( fun i n i t / 0 ) .
%% Synchronous c a l l
o r d e r _ c a t ( Pid , Name , Color , D e s c r i p t i o n ) ->
Ref = e r l a n g : monitor ( p r o c e s s , Pid ) ,
Pid ! { s e l f ( ) , Ref , { o r d e r , Name , Color , D e s c r i p t i o n } } ,
receive
{ Ref , Cat} ->
e r l a n g : demonitor ( Ref , [ f l u s h ] ) ,
Cat ;
{ 'DOWN' , Ref , p r o c e s s , Pid , Reason } ->
e r l a n g : e r r o r ( Reason )
a f t e r 5000 ->
e r l a n g : e r r o r ( timeout )
end .
%% This c a l l i s a s y n c h r o n o u s
r e t u r n _ c a t ( Pid , Cat = #c a t { } ) ->
Pid ! { r e t u r n , Cat} ,
ok .
%% Synchronous c a l l
c l o s e _ s h o p ( Pid ) ->
Ref = e r l a n g : monitor ( p r o c e s s , Pid ) ,
Pid ! { s e l f ( ) , Ref , t e r m i n a t e } ,
receive
{ Ref , ok } ->
e r l a n g : demonitor ( Ref , [ f l u s h ] ) ,
ok ;
{ 'DOWN' , Ref , p r o c e s s , Pid , Reason } ->
e r l a n g : e r r o r ( Reason )
a f t e r 5000 ->
e r l a n g : e r r o r ( timeout )
end .
%%% S e r v e r f u n c t i o n s
i n i t ( ) -> l o o p ( [ ] ) .
l o o p ( Cats ) ->
receive
{ Pid , Ref , { o r d e r , Name , Color , D e s c r i p t i o n } } ->
i f Cats =:= [ ] ->
Pid ! { Ref , make_cat (Name , Color , D e s c r i p t i o n ) } ,

229

end .

l o o p ( Cats ) ;
Cats =/= [ ] -> % g o t t o empty t h e s t o c k
Pid ! { Ref , hd ( Cats ) } ,
l o o p ( t l ( Cats ) )
end ;
{ r e t u r n , Cat = #c a t { } } ->
l o o p ( [ Cat | Cats ] ) ;
{ Pid , Ref , t e r m i n a t e } ->
Pid ! { Ref , ok } ,
t e r m i n a t e ( Cats ) ;
Unknown ->
%% do some l o g g i n g h e r e t o o
i o : format ( "Unknown message : ~p~n" , [ Unknown ] ) ,
l o o p ( Cats )

%%% P r i v a t e f u n c t i o n s
make_cat (Name , Col , Desc ) ->
#c a t {name=Name , c o l o r=Col , d e s c r i p t i o n=Desc } .
t e r m i n a t e ( Cats ) ->
[ i o : format ( "~p was s e t f r e e . ~ n" , [ C#c a t . name ] ) | | C <- Cats ] ,
ok .

/. :
. ,
,
, ,
( , ):
1> c ( k i t t y _ s e r v e r ) .
{ok , k i t t y _ s e r v e r }
2> r r ( k i t t y _ s e r v e r ) .
[ cat ]
3> Pid = k i t t y _ s e r v e r : s t a r t _ l i n k ( ) .
<0.57.0 >
4> Cat1 = k i t t y _ s e r v e r : o r d e r _ c a t ( Pid , c a r l , brown , " l o v e s t o burn
bridges ") .
#c a t {name = c a r l , c o l o r = brown ,
d e s c r i p t i o n = " l o v e s t o burn b r i d g e s " }
5> k i t t y _ s e r v e r : r e t u r n _ c a t ( Pid , Cat1 ) .
ok
6> k i t t y _ s e r v e r : o r d e r _ c a t ( Pid , jimmy , orange , " cuddly " ) .
#c a t {name = c a r l , c o l o r = brown ,
d e s c r i p t i o n = " l o v e s t o burn b r i d g e s " }
7> k i t t y _ s e r v e r : o r d e r _ c a t ( Pid , jimmy , orange , " cuddly " ) .
#c a t {name = jimmy , c o l o r = orange , d e s c r i p t i o n = " cuddly " }
8> k i t t y _ s e r v e r : r e t u r n _ c a t ( Pid , Cat1 ) .
ok

230

9> k i t t y _ s e r v e r : c l o s e _ s h o p ( Pid ) .
c a r l was s e t f r e e .
ok
10> k i t t y _ s e r v e r : c l o s e _ s h o p ( Pid ) .
** e x c e p t i o n e r r o r : no such p r o c e s s o r p o r t
i n f u n c t i o n k i t t y _ s e r v e r : c l o s e _ s h o p /1

. ,
. ,
, , ,
, ..
. ,
, - .
API .
, .
,
.
, ,
:
- module ( my_server ) .
- compile ( export_all ) .
c a l l ( Pid , Msg ) ->
Ref = e r l a n g : monitor ( p r o c e s s , Pid ) ,
Pid ! { s e l f ( ) , Ref , Msg} ,
receive
{ Ref , Reply } ->
e r l a n g : demonitor ( Ref , [ f l u s h ] ) ,
Reply ;
{ 'DOWN' , Ref , p r o c e s s , Pid , Reason } ->
e r l a n g : e r r o r ( Reason )
a f t e r 5000 ->
e r l a n g : e r r o r ( timeout )
end .

PID, ,
.
.
,
my_server , :
- module ( k i t t y _ s e r v e r 2 ) .
- e x p o r t ( [ s t a r t _ l i n k / 0 , o r d e r _ c a t / 4 , r e t u r n _ c a t / 2 , c l o s e _ s h o p /1 ] ) .
- r e c o r d ( cat , {name , c o l o r=green , d e s c r i p t i o n } ) .

231

%%% C l i e n t API
s t a r t _ l i n k ( ) -> spawn_link ( fun i n i t / 0 ) .
%% Synchronous c a l l
o r d e r _ c a t ( Pid , Name , Color , D e s c r i p t i o n ) ->
my_server : c a l l ( Pid , { o r d e r , Name , Color , D e s c r i p t i o n } ) .
%% This c a l l i s a s y n c h r o n o u s
r e t u r n _ c a t ( Pid , Cat = #c a t { } ) ->
Pid ! { r e t u r n , Cat} ,
ok .
%% Synchronous c a l l
c l o s e _ s h o p ( Pid ) ->
my_server : c a l l ( Pid , t e r m i n a t e ) .

, ,
call/2 . ,
, , ,

. ,
, ,
. :
l o o p ( Module , S t a t e ) ->
receive
Message -> Module : h a n d l e ( Message , S t a t e )
end .

:
h a n d l e ( Message1 , S t a t e ) -> NewState1 ;
h a n d l e ( Message2 , S t a t e ) -> NewState2 ;
...
h a n d l e ( MessageN , S t a t e ) -> NewStateN .

. .
kitty_server ( ,
!), ,
,
. ,

, .
,
my_server:loop/2 .
call/2 ,
232


sync :
c a l l ( Pid , Msg ) ->
Ref = e r l a n g : monitor ( p r o c e s s , Pid ) ,
Pid ! { sync , s e l f ( ) , Ref , Msg} ,
receive
{ Ref , Reply } ->
e r l a n g : demonitor ( Ref , [ f l u s h ] ) ,
Reply ;
{ 'DOWN' , Ref , p r o c e s s , Pid , Reason } ->
e r l a n g : e r r o r ( Reason )
a f t e r 5000 ->
e r l a n g : e r r o r ( timeout )
end .

.
cast/2 :
c a s t ( Pid , Msg ) ->
Pid ! { async , Msg} ,
ok .

:
l o o p ( Module , S t a t e ) ->
receive
{ async , Msg} ->
l o o p ( Module , Module : h a n d l e _ c a s t ( Msg , S t a t e ) ) ;
{ sync , Pid , Ref , Msg} ->
l o o p ( Module , Module : h a n d l e _ c a l l ( Msg , Pid , Ref , S t a t e )
)
end .

,
/ (
),

,
,

.

:
(
, leaking abstraction). ,
my_server
,
. -
.
,
233

.
:
l o o p ( Module , S t a t e ) ->
receive
{ async , Msg} ->
l o o p ( Module , Module : h a n d l e _ c a s t ( Msg , S t a t e ) ) ;
{ sync , Pid , Ref , Msg} ->
l o o p ( Module , Module : h a n d l e _ c a l l ( Msg , { Pid , Ref } ,
State ) )
end .

Pid Ref ,
,
From.
. ,
From :
r e p l y ( { Pid , Ref } , Reply ) ->
Pid ! { Ref , Reply } .

( start , start_link
init ), .
, :
- module ( my_server ) .
- e x p o r t ( [ s t a r t / 2 , s t a r t _ l i n k / 2 , c a l l / 2 , c a s t / 2 , r e p l y /2 ] ) .
%%% P u b l i c API
s t a r t ( Module , I n i t i a l S t a t e ) ->
spawn ( fun ( ) -> i n i t ( Module , I n i t i a l S t a t e ) end ) .
s t a r t _ l i n k ( Module , I n i t i a l S t a t e ) ->
spawn_link ( fun ( ) -> i n i t ( Module , I n i t i a l S t a t e ) end ) .
c a l l ( Pid , Msg ) ->
Ref = e r l a n g : monitor ( p r o c e s s , Pid ) ,
Pid ! { sync , s e l f ( ) , Ref , Msg} ,
receive
{ Ref , Reply } ->
e r l a n g : demonitor ( Ref , [ f l u s h ] ) ,
Reply ;
{ 'DOWN' , Ref , p r o c e s s , Pid , Reason } ->
e r l a n g : e r r o r ( Reason )
a f t e r 5000 ->
e r l a n g : e r r o r ( timeout )
end .
c a s t ( Pid , Msg ) ->

234

Pid ! { async , Msg} ,


ok .
r e p l y ( { Pid , Ref } , Reply ) ->
Pid ! { Ref , Reply } .
%%% P r i v a t e s t u f f
i n i t ( Module , I n i t i a l S t a t e ) ->
l o o p ( Module , Module : i n i t ( I n i t i a l S t a t e ) ) .
l o o p ( Module , S t a t e ) ->
receive
{ async , Msg} ->
l o o p ( Module , Module : h a n d l e _ c a s t ( Msg , S t a t e ) ) ;
{ sync , Pid , Ref , Msg} ->
l o o p ( Module , Module : h a n d l e _ c a l l ( Msg , { Pid , Ref } ,
State ) )
end .

. kitty_server2
(callback module),
, my_server .
, ,
my_server :
- module ( k i t t y _ s e r v e r 2 ) .
- e x p o r t ( [ s t a r t _ l i n k / 0 , o r d e r _ c a t / 4 , r e t u r n _ c a t / 2 , c l o s e _ s h o p /1 ] ) .
- e x p o r t ( [ i n i t / 1 , h a n d l e _ c a l l / 3 , h a n d l e _ c a s t /2 ] ) .
- r e c o r d ( cat , {name , c o l o r=green , d e s c r i p t i o n } ) .
%%% C l i e n t API
s t a r t _ l i n k ( ) -> my_server : s t a r t _ l i n k ( ?MODULE, [ ] ) .
%% Synchronous c a l l
o r d e r _ c a t ( Pid , Name , Color , D e s c r i p t i o n ) ->
my_server : c a l l ( Pid , { o r d e r , Name , Color , D e s c r i p t i o n } ) .
%% This c a l l i s a s y n c h r o n o u s
r e t u r n _ c a t ( Pid , Cat = #c a t { } ) ->
my_server : c a s t ( Pid , { r e t u r n , Cat} ) .
%% Synchronous c a l l
c l o s e _ s h o p ( Pid ) ->
my_server : c a l l ( Pid , t e r m i n a t e ) .

, -export()
235

. , my_server - :
%%% S e r v e r f u n c t i o n s
i n i t ( [ ] ) -> [ ] . %% no t r e a t m e n t o f i n f o h e r e !
h a n d l e _ c a l l ( { o r d e r , Name , Color , D e s c r i p t i o n } , From , Cats ) ->
i f Cats =:= [ ] ->
my_server : r e p l y ( From , make_cat (Name , Color , D e s c r i p t i o n )
),
Cats ;
Cats =/= [ ] ->
my_server : r e p l y ( From , hd ( Cats ) ) ,
t l ( Cats )
end ;
h a n d l e _ c a l l ( t e r m i n a t e , From , Cats ) ->
my_server : r e p l y ( From , ok ) ,
t e r m i n a t e ( Cats ) .
h a n d l e _ c a s t ( { r e t u r n , Cat = #c a t { } } , Cats ) ->
[ Cat | Cats ] .

(private) :
%%% P r i v a t e f u n c t i o n s
make_cat (Name , Col , Desc ) ->
#c a t {name=Name , c o l o r=Col , d e s c r i p t i o n=Desc } .
t e r m i n a t e ( Cats ) ->
[ i o : format ( "~p was s e t f r e e . ~ n" , [ C#c a t . name ] ) | | C <- Cats ] ,
e x i t ( normal ) .

, , ok ,
, exit(normal) terminate/1 ,
.
,
. ,
, .
16.4

OTP ( ).
OTP: ,
, ,
,
236

. ,
, .
, ,
. ,
. ,
,
, .
, , ,
.
,
Erlang.
, (
, ),
, , ..

-.
.
, , ,
. ,
.
,
my_server , .
, (,
!), ,
, ..

.

,
(
).
,
.

my_server:call/3 ,
,
,
,
. ,
- ,
237

. ,
,
.
, ,
,
. -
,
, ,
. ,
, 'handle_call/3' 'handle_cast/2',
.
, .
. ,
.
,
, .

,
, ,
.
,
. , Erlang- OTP.
.
: , -,
, ,
,
, ,
,
.. ,
.
,
.
( , ),
Erlang/OTP
gen_server. gen_server my_server
, ,
.

238

17

17.1

,
, .
gen_server
, my_server
16.3.
,

,
gen_server .
17.1.1

 init/1.
, my_server , ,
,
, .
{ok, State} , {ok, State, TimeOut} , {ok, State, hibernate} ,
{stop, Reason} ignore .
{ok, State} , ,
. , State
, ,
. TimeOut
, ,
, .
,
239

( timeout ), handle_info/2
( ).
, , ,
, , ,
,
hibernate . , ,
,
. , ,
, .
{stop, Reason} ,
- .
: .
, - ,
.
erlang:hibernate(M,F,A),
( ).
,
(heap), ,
. , ,
, .
, M:F
A , .

: , init/1 ,

, . -
, 'ready',
gen_server , ,
.
17.1.2

handle_call

handle_call/3
( , ).
3 : Request, From State. ,
handle_call/3 my_server .
, .
,
my_server:reply/2 . gen_server
8 , .
, :
{ r e p l y , Reply , NewState }

240

{ r e p l y , Reply , NewState , Timeout }


{ r e p l y , Reply , NewState , h i b e r n a t e }
{ n o r e p l y , NewState }
{ n o r e p l y , NewState , Timeout }
{ n o r e p l y , NewState , h i b e r n a t e }
{ stop , Reason , Reply , NewState }
{ stop , Reason , NewState }

Timeout hibernate
, init/1 . Reply,
, . ,
noreply .
noreply , ,
.
gen_server:reply/2,
, my_server:reply/2 .

reply . noreply
. ,
, (!
!),
( ), ..
, gen_server:reply/2 ,
- .
17.1.3

handle_cast

(callback) handle_cast/2
, my_server .
Message State,
. ,
handle_call/3 .
:
:
{ n o r e p l y , NewState }
{ n o r e p l y , NewState , Timeout }
{ n o r e p l y , NewState , h i b e r n a t e }
{ stop , Reason , NewState }

241

17.1.4

handle_info

, , ,
? , handle_info/2
. handle_cast/2
. ,
,
! , timeout
init/1 , 'EXIT' .
17.1.5

terminate

terminate/2 ,
handle_ {stop, Reason, NewState} ,
{stop, Reason, Reply, NewState} . : Reason
State, stop .
terminate/2 , (,
), , , gen_server
(trapping exits).

: terminate/2 ,
normal , shutdown {shutdown, Term} ,
OTP
.
 init/1 , terminate/2
init/1 .
,
, , . ,
, ETS ,
.. , , ,
,
.
17.1.6

code_change

code_change/3
(upgrade) . code_change(PreviousVersion, State, Extra) .
PreviousVersion , ,
( , ,
4.4), {down, Version} ,
242

(downgrade) ( ). State
, ,
.
,
orddict. orddict ,
dict.
,
. {ok, NewState} .
Extra
.
OTP
,
,

. .
,
. ,
: OTP
.
A, B,
B
A.
, gen_server .
17.2

.BEAM me up, Scotty!

kitty_gen_server.
kitty_server2 , API.
, :
- module ( k i t t y _ g e n _ s e r v e r ) .
- behaviour ( gen_server ) .

. -
:
1> c ( k i t t y _ g e n _ s e r v e r ) .
. / k i t t y _ g e n _ s e r v e r . e r l : 2 : Warning : u n d e f i n e d c a l l b a c k f u n c t i o n
code_change /3 ( b e h a v i o u r ' g e n _ s e r v e r ' )
. / k i t t y _ g e n _ s e r v e r . e r l : 2 : Warning : u n d e f i n e d c a l l b a c k f u n c t i o n
h a n d l e _ c a l l /3 ( b e h a v i o u r ' g e n _ s e r v e r ' )

243

. / k i t t y _ g e n _ s e r v e r . e r l : 2 : Warning : u n d e f i n e d
h a n d l e _ c a s t /2 ( b e h a v i o u r ' g e n _ s e r v e r ' )
. / k i t t y _ g e n _ s e r v e r . e r l : 2 : Warning : u n d e f i n e d
h a n d l e _ i n f o /2 ( b e h a v i o u r ' g e n _ s e r v e r ' )
. / k i t t y _ g e n _ s e r v e r . e r l : 2 : Warning : u n d e f i n e d
i n i t /1 ( b e h a v i o u r ' g e n _ s e r v e r ' )
. / k i t t y _ g e n _ s e r v e r . e r l : 2 : Warning : u n d e f i n e d
t e r m i n a t e /2 ( b e h a v i o u r ' g e n _ s e r v e r ' )
{ok , k i t t y _ g e n _ s e r v e r }

callback function
callback function
callback function
callback function

,
. -
gen_server . , ,
,
.  ,
, (
).
: , Erlang
: 'behavior' 'behaviour'.
.
behaviour_info/1 ,
:
- module ( my_behaviour ) .
- e x p o r t ( [ b e h a v i o u r _ i n f o /1 ] ) .
%% i n i t / 1 , some_fun /0 and o t h e r /3 a r e now e x p e c t e d c a l l b a c k s
b e h a v i o u r _ i n f o ( c a l l b a c k s ) -> [ { i n i t , 1 } , {some_fun , 0 } , { o t h e r , 3 }
];
b e h a v i o u r _ i n f o (_) -> u n d e f i n e d .

, , , .
, ,
-behaviour(my_behaviour) ,
, .
.
start_link/0 .
:
s t a r t _ l i n k ( ) -> g e n _ s e r v e r : s t a r t _ l i n k ( ?MODULE, [ ] , [ ] ) .

,
, init/1 ,
,
.
, , .
244

, pid,
{ok, Pid} . :
%% Synchronous c a l l
o r d e r _ c a t ( Pid , Name , Color , D e s c r i p t i o n ) ->
g e n _ s e r v e r : c a l l ( Pid , { o r d e r , Name , Color , D e s c r i p t i o n } ) .
%% This c a l l i s a s y n c h r o n o u s
r e t u r n _ c a t ( Pid , Cat = #c a t { } ) ->
g e n _ s e r v e r : c a s t ( Pid , { r e t u r n , Cat} ) .
%% Synchronous c a l l
c l o s e _ s h o p ( Pid ) ->
g e n _ s e r v e r : c a l l ( Pid , t e r m i n a t e ) .

. ,
gen_server:call/2-3 ,
-. - ( innity ),
5 .
, .
gen_server.
:

gen_server

YourModule

start/3-4

init/1

start_link/3-4

init/1

call/2-3

handle_call/3

cast/2
handle_cast/2
,
:
handle_info/2
terminate/2
code_change/3
init/1 , handle_call/3 handle_cast/2 ,
, .
%%% S e r v e r f u n c t i o n s
i n i t ( [ ] ) -> {ok , [ ] } . %% no t r e a t m e n t o f i n f o h e r e !
h a n d l e _ c a l l ( { o r d e r , Name , Color , D e s c r i p t i o n } , _From , Cats ) ->
i f Cats =:= [ ] ->

245

{ r e p l y , make_cat (Name , Color , D e s c r i p t i o n ) , Cats } ;


Cats =/= [ ] ->
{ r e p l y , hd ( Cats ) , t l ( Cats ) }

end ;
h a n d l e _ c a l l ( t e r m i n a t e , _From , Cats ) ->
{ stop , normal , ok , Cats } .

h a n d l e _ c a s t ( { r e t u r n , Cat = #c a t { } } , Cats ) ->


{ n o r e p l y , [ Cat | Cats ] } .

.
, .
.  handle_info/2 .
,
,
(unexpected) :
h a n d l e _ i n f o ( Msg , Cats ) ->
i o : format ( " Unexpected message : ~p~n" , [ Msg ] ) ,
{ n o r e p l y , Cats } .

 terminate/2 .
(private) terminate/1 ,
:
t e r m i n a t e ( normal , Cats ) ->
[ i o : format ( "~p was s e t f r e e . ~ n" , [ C#c a t . name ] ) | | C <- Cats ] ,
ok .

 code_change/3 :
code_change ( _OldVsn , S t a t e , _Extra ) ->
%% No change planned . The f u n c t i o n i s t h e r e f o r t h e be havi our
,
%% but w i l l not be used . Only a v e r s i o n on t h e next
{ok , S t a t e } .

(private) make_cat/3 :
%%% P r i v a t e f u n c t i o n s
make_cat (Name , Col , Desc ) ->
#c a t {name=Name , c o l o r=Col , d e s c r i p t i o n=Desc } .

:
1> c ( k i t t y _ g e n _ s e r v e r ) .
{ok , k i t t y _ g e n _ s e r v e r }
2> r r ( k i t t y _ g e n _ s e r v e r ) .
[ cat ]

246

3> {ok , Pid } = k i t t y _ g e n _ s e r v e r : s t a r t _ l i n k ( ) .


{ok , <0.253.0 > }
4> Pid ! <<" Test h a n d l e _ i n f o ">>.
Unexpected message : <<" Test h a n d l e _ i n f o ">>
<<" Test h a n d l e _ i n f o ">>
5> Cat = k i t t y _ g e n _ s e r v e r : o r d e r _ c a t ( Pid , "Cat S t e v e n s " , white , "
not a c t u a l l y a c a t " ) .
#c a t {name = "Cat S t e v e n s " , c o l o r = white ,
d e s c r i p t i o n = " not a c t u a l l y a c a t " }
6> k i t t y _ g e n _ s e r v e r : r e t u r n _ c a t ( Pid , Cat ) .
ok
7> k i t t y _ g e n _ s e r v e r : o r d e r _ c a t ( Pid , " K i t t e n M i t t e n s " , b lack , " l o o k
a t them l i t t l e paws ! " ) .
#c a t {name = "Cat S t e v e n s " , c o l o r = white ,
d e s c r i p t i o n = " not a c t u a l l y a c a t " }
8> k i t t y _ g e n _ s e r v e r : o r d e r _ c a t ( Pid , " K i t t e n M i t t e n s " , b lack , " l o o k
a t them l i t t l e paws ! " ) .
#c a t {name = " K i t t e n M i t t e n s " , c o l o r = bla ck ,
d e s c r i p t i o n = " l o o k a t them l i t t l e paws ! " }
9> k i t t y _ g e n _ s e r v e r : r e t u r n _ c a t ( Pid , Cat ) .
ok
10> k i t t y _ g e n _ s e r v e r : c l o s e _ s h o p ( Pid ) .
"Cat S t e v e n s " was s e t f r e e .
ok

, !

? ,
, :

.
, ,
,
.
- ,
.
, , ,
.
.

247

18

18.1

()
.
. ,
. ,
( ) .
: ,

.
.
, , .
, ,
. Erlang
248

(, , ).
: ,
, , , ,
.
:

,
.
, ,
Erlang:
- module ( cat_fsm ) .
- e x p o r t ( [ s t a r t / 0 , e v e n t /2 ] ) .
s t a r t ( ) ->
spawn ( fun ( ) -> dont_give_crap ( ) end ) .
e v e n t ( Pid , Event ) ->
Ref = make_ref ( ) , % won ' t c a r e f o r m o n i t o r s h e r e
Pid ! { s e l f ( ) , Ref , Event } ,
receive
{ Ref , Msg} -> {ok , Msg}
a f t e r 5000 ->
{ error , timeout }
end .
dont_give_crap ( ) ->
receive
{ Pid , Ref , _Msg} -> Pid ! { Ref , meh} ;
_ -> ok
end ,
i o : format ( " S w i t c h i n g t o ' dont_give_crap ' s t a t e ~n" ) ,
dont_give_crap ( ) .

249

, ,
:
1> c ( cat_fsm ) .
{ok , cat_fsm }
2> Cat = cat_fsm : s t a r t ( ) .
<0.67.0 >
3> cat_fsm : e v e n t ( Cat , p e t ) .
S w i t c h i n g t o ' dont_give_crap ' s t a t e
{ok , meh}
4> cat_fsm : e v e n t ( Cat , l o v e ) .
S w i t c h i n g t o ' dont_give_crap ' s t a t e
{ok , meh}
5> cat_fsm : e v e n t ( Cat , c h e r i s h ) .
S w i t c h i n g t o ' dont_give_crap ' s t a t e
{ok , meh}

,
. ,
:
- module ( dog_fsm ) .
- e x p o r t ( [ s t a r t / 0 , s q u i r r e l / 1 , p e t /1 ] ) .
s t a r t ( ) ->
spawn ( fun ( ) -> bark ( ) end ) .
s q u i r r e l ( Pid ) -> Pid ! s q u i r r e l .
p e t ( Pid ) -> Pid ! p e t .
bark ( ) ->
i o : format ( "Dog s a y s : BARK! BARK! ~n" ) ,
receive
p e t ->
wag_tail ( ) ;
_ ->
i o : format ( "Dog i s c o n f u s e d ~n" ) ,
bark ( )
a f t e r 2000 ->
bark ( )
end .
wag_tail ( ) ->
i o : format ( "Dog wags i t s t a i l ~n" ) ,
receive
p e t ->
s i t () ;
_ ->
i o : format ( "Dog i s c o n f u s e d ~n" ) ,

250

wag_tail ( )
a f t e r 30000 ->
bark ( )
end .
s i t ( ) ->
i o : format ( "Dog i s s i t t i n g . Gooooood boy ! ~n" ) ,
receive
s q u i r r e l ->
bark ( ) ;
_ ->
i o : format ( "Dog i s c o n f u s e d ~n" ) ,
s i t ()
end .


, , , .
:
6> c ( dog_fsm ) .
{ok , dog_fsm}
7> Pid = dog_fsm : s t a r t ( ) .
Dog s a y s : BARK! BARK!
<0.46.0 >
Dog s a y s : BARK! BARK!
Dog s a y s : BARK! BARK!
Dog s a y s : BARK! BARK!
8> dog_fsm : p e t ( Pid ) .
pet
Dog wags i t s t a i l
9> dog_fsm : p e t ( Pid ) .
Dog i s s i t t i n g . Gooooood boy !
pet
10> dog_fsm : p e t ( Pid ) .
Dog i s c o n f u s e d
pet
Dog i s s i t t i n g . Gooooood boy !
11> dog_fsm : s q u i r r e l ( Pid ) .
Dog s a y s : BARK! BARK!
squirrel
Dog s a y s : BARK! BARK!
12> dog_fsm : p e t ( Pid ) .
Dog wags i t s t a i l
pet
13> %% w a i t 30 s e c o n d s
Dog s a y s : BARK! BARK!
Dog s a y s : BARK! BARK!
Dog s a y s : BARK! BARK!
13> dog_fsm : p e t ( Pid ) .

251

Dog wags i t s t a i l
pet
14> dog_fsm : p e t ( Pid ) .
Dog i s s i t t i n g . Gooooood boy !
pet

, , (
 , ).
,
Erlang. - :
. -
.
init terminate ,
..

 , .

, - ,
.
,  ,
.
" ".
smell_food ,
, .

.
gen_fsm .
18.2

gen_fsm gen_server ,
.
, (calls)
(casts) .
, ,
. ,
.

252

18.2.1

init

init/1,
, :
{ok, StateName, Data} , {ok, StateName, Data, Timeout} ,
{ok, StateName, Data, hibernate} {stop, Reason} .
stop gen_server -.
hibernate Timeout.
StateName. StateName
, ,
.
18.2.2

StateName

StateName/2 StateName/3
,
. , init/1
{ok, sitting, dog} . ,

sitting . ,
gen_server ,
sit ,
bark wag_tail
, .
,
.
,
- .

, , ,
.
, , , .
,
.
. init/1 ,
sitting .
gen_fsm , sitting/2 ,
sitting/3 . sitting/2 ,
sitting/3 .
253

You might also like