Сергей Игнатов, JetBrains
Сергей Игнатов,
sergey.ignatov@jetbrains.com
+--------+ +--------+
| Erlang | | Elixir |
+--------+ +--------+
|| ||
\/ \/
+-----------------+
| .beam byte code |
+-----------------+
||
\/
+---------------------------+
| BEAM emulator (Erlang VM) |
+---------------------------+
1 + 2 * 3. % 7
1 * 1.0 * 7. % 7.0
1.0e1 - 3. % 7.0
2#11 + 3#11. % 7
16#AE. % 174
Основание
#Значение
(основание от 2
до 36
)
ok.
{error, badarg}.
'CAPS_ATOM'.
'with spaces'.
'atom' = atom. % true
:symbol
из Ruby, 'quoted-value
из Lisp
Атом — просто уникальное значение
true
и false
— тоже атомы
{"String", 200}.
element(1, {"String", 200}). % "String"
setelement(2, {"String", 200}, 250). % {"String",250}
Неизменяемые структуры, всегда возвращается новый экземпляр.
[1,2,3].
[1,2,a,"str",3,{}].
[4 | [1,2,3]]. % [4,1,2,3]
[1,2,3] ++ [4,5]. % [1,2,3,4,5]
[1,2,3] -- [1,2] -- [2]. % [2,3]
hd([4,1,2,3]). % 4
tl([4,1,2,3]). % [1,2,3]
tl(["last element"]). % []
Символ «|
» — это оператор добавления элемента в голову списка
[2*X || X <- lists:seq(0,10), X*X > 3]. % [4,6,8,10]
[X*X || X <- [1,2,3,4,5,6,7], X > 6]. % [49]
[X || X <- [1,2,foo,bar,5,6], X rem 2 == 0]. % [2,6]
Color = 16#F09A29.
Pixel = <<Color:24>>.
Pixels = <<213,45,132,64,76,32,76,0,0,234,32,15>>.
<<Pix1:24, Pix2:24, Pix3:24, Pix4:24>> = Pixels.
<<R:8, G:8, B:8>> = <<Pix1:24>>.
<<R:8, Rest/binary>> = Pixels.% R=213,Rest = <<45,132,64...>>
Это действительно удобный способ чтения бинарных данных
Важно: необходим пробел между =
и <<
Pixels = <<213,45,132,64,76,32,76,0,0,234,32,15>>.
RGB = [{R,G,B} || <<R:8,G:8,B:8>> <= Pixels].
RGB = [{213,45,132},{64,76,32},{76,0,0},{234,32,15}].
[X || <<X>> <= <<1,2,3,4,5>>, X rem 2 == 0]. % [2,4]
"Just a string".
[65,66,67]. % "ABC"
[97,98,99]. % "abc"
[97,98,99] == "abc". % true
Строка — список целых чисел.
Res = ok. % ok
Primes = [1,2,3,5,7]. % [1,2,3,5,7]
C = {"A", 20}. % {"A",20}
L = [C, {"B", 25}]. % [{"A",20},{"B",25}]
Присваиваний нет. Есть связывание и сопоставление с образцом.
Name = onlyonce. % onlyonce
Name = maybetwice. % error
ok = ok. % ok
ok = notok. % error
N = 12. % 12
12 = N. % 12
{[], M} = {[], 200}. % M = 200
[Head|Tail] = [1,2,3,4]. % Head = 1, Tail = [2,3,4]
M = #{1 => 1}.
M2 = M#{1 => 10}.
#{1 := X} = M2.
X. % 10
#{2 := X3} = M. % ** exception error:
% no match of right hand side value #{1 => 1}
Опять же, персистентная структура данных.
5 =:= true. % false
0 == false. % false
"a" > 10. % true
1.0 == 1. % true
1.0 =:= 1. % false
0 > atom. % false
sort([atom,[],{},1]). % [1,atom,{},[]]
number < atom < reference < fun < port < pid < tuple < list < bit string
-module(simple).
-export([add/2, hello/0]).
add(A, B) -> internal(A, B).
internal(A, B) -> A + B.
hello() -> io:format("Hello, world!~n").
Имя файла должно совпадать с именем модуля.
forms ::= (form .)*
form ::= function | attribute
function ::= function_clause (; function_clause)*
function_clause ::= atom ( args? ) guards? -> body
body ::= expression (, expression)*
head([H|_]) -> H.
second([_, S|_]) -> S.
same(X, X) -> true;
same(_, _) -> false.
right_age(Age)
when Age >=16 ,Age <104 -> true; right_age(_) -> false. to_string(Arg)when is_atom(Agr) -> "atom"; to_string(Arg)when is_list(Agr) -> "list"; to_string(Arg)when is_integer(Agr) -> "integer"; to_string(_) -> "unknown".function_clause ::= atom ( args? ) guards? -> body
-module(greet).
-export([say/2]).
say(Gender, Name) ->
io:format("Hello, " ++ title(Gender) ++ ". " ++ Name).
title(male) -> "Mr";
title(female) -> "Mr";
title(_) -> "".
-module(greet).
-export([say/2]).
say(Gender, Name) ->
Title = case Gender of
male -> "Mr" ;
female -> "Mrs";
_ -> ""
end,
io:format("Hello, " ++ Title ++ ". " ++ Name).
works_fine() -> if 1 == 1 -> fine end.
throws_error() -> if 1 == 2 -> fine end.
Всегда должна быть ветка по которой пойдет исполнение:
even_or_odd(Num) ->
if
Num rem 2 == 0 -> even;
true -> odd
end.
len([]) -> 0;
len([_|T]) -> 1 + len(T).
reverse([]) -> [];
reverse([H|T]) -> reverse(T) ++ [H].
map(_, []) -> [];
map(Fun, [Head|Tail]) -> [Fun(Head)|map(Fun, Tail)].
len(L) -> len(L, 0).
len([], Acc) -> Acc;
len([_|T], Acc) -> len(T, Acc + 1).
reverse(L) -> reverse(L, []).
reverse([], Acc) -> Acc;
reverse([H|T], Acc) -> reverse(T, [H|Acc]).
map(Fun, [Head|Tail]) -> ...
map(_, []) -> [];
map(Fun, [Head|Tail]) -> [Fun(Head)|map(Fun, Tail)].
map(fun (X) -> X + 1 end , [1,2,3]). % [2,3,4]
map(fun (X) -> X * X end , [1,2,3]). % [1,4,9]
-module(records).
-export([create_bender/0]).
-record(robot, {name, occupation=none,
hobbies, details=[]}).
create_bender() ->
#robot{name="Bender Bending Rodríguez",
occupation=industrial, hobbies=["Kill all humans"],
details=["Powered by alcohol-based fuels"]}.
-define(head, -module(test)).
?head.
-define(Arity, 2).
-define(name, main).
-export([?name/?Arity]).
-define(Value, ?Arity).
-define(add(A, B), A + B).
-define(title, ?name(X, Y) ->).
?title ?add(X, Y) + ?Value.
-spec(add_one(number()) -> number()).
add_one(X) -> X + 1.
-spec(atom_add() -> number()).
atom_add() -> add_one(2).
-spec(tuple_sum({number(), number()}) -> number()).
tuple_sum({X, Y}) -> X + Y.
Dialyzer
проверяет корректность контрактов.
Typer
поможет вывести информацию о типах из исходного кода.
-type suit() :: spades | clubs | hearts | diamonds.
-type value() :: 1 ..10 | j | q | k.
-type card() :: {suit(), value()}.
kind({_, A}) when A >= 1 , A =< 10 -> number;
kind(_) -> face.
main() ->
number = kind({spades, 7}),
face = kind({hearts, k}),
number = kind({rubies, 4}). % error
Актор — это и есть процесс, связанный с ним «почтовый ящик
» и уникальный идентификатор (pid
)
Pid = spawn(Node, Module, Function, Args).
HW = spawn(fun() -> io:format("hello world") end).
G = fun(X) -> timer:sleep(10), io:format("~p~n", [X]) end.
[spawn(fun() -> G(X) end) || X <- lists:seq(1,10)].
self()
— pid текущего процесса.
Pid ! Message.
Self = self().
Self ! ok.
Self ! {[], 1, atom, "string"}.
Self ! Self.
receive
Pattern1 -> ...;
Pattern2 -> ...;
PatternN -> ...
after Timeout ->
...
end.
F = fun() -> timer:sleep(500), exit(reason) end.
spawn(F). % Pid
link(spawn(F)). % ** exception error 'reason'
spawn_link(F).
spawn_link(Node, Module, Fun, Args).
unlink(Pid).
Между процессами не может быть больше одной ссылки.
Цепочки процессов "погибают" до системного.
process_flag(trap_exit, true)
сделает вас системным.
1> monitor(process, spawn(fun () -> timer:sleep(500) end )).
#Ref<0.0.0.77>
2> flush().
Shell got {'DOWN',#Ref<0.0.0.77>,process,<0.63.0>,normal}
spawn_monitor(Function).
spawn_monitor(Module, Function, Args).
demonitor(Ref).
Может создать любое количество мониторов между процессами.
try Expression of
SuccessfulPattern1 [Guards] -> ...;
SuccessfulPattern2 [Guards] -> ...
catch
Exception:Reason -> ...;
Error:What -> ...
end.
1> self().
<0.32.0>
2> X = 1/0.
** exception error: bad argument in an arithmetic expression
3> self().
<0.35.0>
4> X = (catch 1/0).
{'EXIT',{badarith,[{erlang,'/',[1,0],[]}}
5> self().
<0.35.0>