Erlang Introduction

Post on 24-Dec-2014

1.095 views 5 download

description

 

Transcript of Erlang Introduction

Erlang IntroductionSerhiy Oplakanets, Lviv 2012

Friday, February 10, 12

Classification

• high-level

• general-purpose

• garbage-collected

• dynamically typed

• functional

• concurrent

Friday, February 10, 12

$ erlErlang R14B04 (erts-5.8.5) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5 (abort with ^G)1>

Friday, February 10, 12

Syntax

Friday, February 10, 12

Data Types

Friday, February 10, 12

1> 2 + 2.4

2> 3 * 5.15

3> 7 / 6.1.1666666666666667

Friday, February 10, 12

1> [].[]

2> [1, 2, 3].[1,2,3]

3> [101,104,63]."eh?"

Friday, February 10, 12

1> "a string"."a string"

2> [97,32,115,116,114,105,110,103]."a string"

Friday, February 10, 12

1> $H.722> $e.1013> $l.1084> $o.1115> [$H, $e, $l, $l, $o]."Hello"

Friday, February 10, 12

1> true.true2> false.false3> true == false.false4> false == false.true5> true /= false.true

Friday, February 10, 12

1> atom.atom

2> anotherAtom.anotherAtom

3> 'One more atom?'.'One more atom?'

Friday, February 10, 12

4> is_atom('One more atom?').true

Friday, February 10, 12

1> is_atom(true).true

2> is_atom(false).true

Friday, February 10, 12

1> {1,2,3}.{1,2,3}

2> {16, "hello"}.{16,"hello"}

3> {3.14, "Pi", {"foo", bar}}.{3.14,"Pi",{"foo",bar}}

Friday, February 10, 12

Invariable Variables

Friday, February 10, 12

1> Variable = "value"."value"

2> AnotherVariable = 128.128

Friday, February 10, 12

1> R = 5, Pi = 3.14.3.14

2> Pi.3.14

3> Pi * R * R.78.5

Friday, February 10, 12

1> X = 1.1

3> X = 2.** exception error: no match of right hand side value 2

4> X = 1.1?!?!

Friday, February 10, 12

Pattern Matching

Friday, February 10, 12

1> X = 1, Y = 1.12> X = Y.???

Friday, February 10, 12

1> UnboundVariable.* 1: variable 'UnboundVariable' is unbound

Friday, February 10, 12

1> X = 1.12> X.13> Y. * 1: variable 'Y' is unbound4> Y = 2.25> Y.2

Friday, February 10, 12

1> User = {"John", "Doe", 35}....2> {Name, Surname, Age} = User....3> Name."John"4> Age.35

Friday, February 10, 12

1> User = {"John", "Doe", 35}....2> {Name, Surname} = User.** exception error: no match of right hand side value {"John","Doe",35}

Friday, February 10, 12

2> User = {"John", "Doe", 35}....3> {Name, "Doe", 35} = User....4> Name."John"

Friday, February 10, 12

1> User = {"John", "Doe", 35}....2> {Name, _, Age} = User....3> Age.354> Name."John"

Friday, February 10, 12

1> _ = 1. 1

2> _.* 1: variable '_' is unbound

5> _ = 3.3

Friday, February 10, 12

1> [Head | Tail] = [1,2,3].[1,2,3]

2> Head.1

3> Tail.[2,3]

Friday, February 10, 12

1> [1 | [2 | [3]]].[1,2,3]

Friday, February 10, 12

Modules and Functions

Friday, February 10, 12

-module(test).-export([main/0]).

main() -> "Hello".

Friday, February 10, 12

1> test:main()."Hello"

Friday, February 10, 12

-module(test).-export([factorial/1]).

factorial(0) -> 1;factorial(N) -> N * factorial(N - 1).

Friday, February 10, 12

$ erlc test.erl $ erl ...1> test:factorial(3).62> test:factorial(5).120

Friday, February 10, 12

-module(logger).-export([log/1, log/2]).

log(Msg) -> {"info", Msg}.log(Level, Msg) -> {Level, Msg}.

--------------------8<--------------------

1> logger:log("Some info message.").{"info","Some info message."}2> logger:log("error", "Kernel panic!"). {"error","Kernel panic!"}

Friday, February 10, 12

log(Msg) -> log("info", Msg).log(Level, Msg) -> {Level, Msg}.

Friday, February 10, 12

Function Guards

Friday, February 10, 12

-module(test).-export([fib/1]).fib(0) -> 0;fib(1) -> 1;fib(N) when N > 0 -> fib(N-1) + fib(N-2).

Friday, February 10, 12

test:fib(0).03> test:fib(1).15> test:fib(8).216> test:fib(-23).** exception error: no function clause matching test:fib(-23)

Friday, February 10, 12

% Refactored factorial function:

factorial(0) -> 1;

factorial(N)when is_integer(N) and (N > 0) -> N * factorial(N - 1);

factorial(_) ->{error, "Invalid argument"}.

Friday, February 10, 12

7> factorial:factorial(3). 6

8> factorial:factorial(0).1

9> factorial:factorial(-1).{error,"Invalid argument"}

10> factorial:factorial("a").{error,"Invalid argument"}

Friday, February 10, 12

Concurrency

• any function can become a process

• process is a function executing in parallel

• process shares nothing with other processes

Friday, February 10, 12

Processes/Actors

• processes are extremely lightweight and fast

• ~15 seconds to spawn 100k processes on my machine (MacBook Pro 8.1, OSX)

Friday, February 10, 12

spawn(Module, Function, Arguments) -> Pid

Friday, February 10, 12

Any function can become a process

Friday, February 10, 12

8> io:format("Hello~n").

Hello

...

2> spawn(io, format, ["Hello~n"]).

Hello

...

Friday, February 10, 12

-module(actor).-export([loop/0]).

loop() -> receive die -> io:format("Exiting~n") end.

Friday, February 10, 12

2> Pid = spawn(actor, loop, []).<0.40.0>3> is_process_alive(Pid).true4> Pid ! die.Exitingdie5> is_process_alive(Pid).false

Friday, February 10, 12

loop() -> receive die -> io:format("Exiting~n"); Msg -> io:format("Got: ~p~n", [Msg]) end.

Friday, February 10, 12

2> Pid = spawn(actor, loop, [])....3> is_process_alive(Pid).true4> Pid ! "Hello".Got: "Hello"...5> is_process_alive(Pid).false

Friday, February 10, 12

loop() -> receive die -> io:format("Exiting~n"); Msg -> io:format("Got: ~p~n", [Msg]), loop() end.

Friday, February 10, 12

2> Pid = spawn(actor, loop, [])....3> Pid ! "Hello".Got: "Hello"4> is_process_alive(Pid).true5> Pid ! "Hello again!".Got: "Hello again!"6> is_process_alive(Pid).true7> Pid ! die.Exiting8> is_process_alive(Pid).false

Friday, February 10, 12

Processes are executed in parallel and share no

data

Friday, February 10, 12

-module(counter).-export([loop/1]).

loop(N) -> receive increment -> loop(N + 1); decrement -> loop(N - 1); print -> io:format("Current counter value: ~w~n", [N]), loop(N) end.

Friday, February 10, 12

2> Counter = spawn(counter, loop, [0])....3> Counter ! increment....4> Counter ! increment....5> Counter ! print. Current counter value: 2...6> Counter ! decrement....7> Counter ! print. Current counter value: 1

Friday, February 10, 12

2> C1 = spawn(counter, loop, [0]). <0.40.0>3> C2 = spawn(counter, loop, [10]).<0.42.0>

4> C1 ! increment, C1 ! increment, C1 ! print. Current counter value: 2

5> C2 ! decrement, C2 ! print. Current counter value: 9

Friday, February 10, 12

Distributed Erlang

Friday, February 10, 12

spawn(Node, Module, Function, Args) -> Pid

Friday, February 10, 12

1> spawn(DistributedNode, test, factorial, [10]).

Friday, February 10, 12

s erl -sname slave -setcookie '123!@#qwe'

...

(slave@Serhiys-MacBook-Pro)1> node().

'slave@Serhiys-MacBook-Pro'

Friday, February 10, 12

$ erl -sname master -setcookie '123!@#qwe'

...

(master@Serhiys-MacBook-Pro)1> net_adm:ping('slave@Serhiys-MacBook-Pro').

pong

(master@Serhiys-MacBook-Pro)3>spawn('slave@Serhiys-MacBook-Pro', factorial, factorial, [100]).

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

<6619.52.0>

Friday, February 10, 12

Fault Tolerance

Friday, February 10, 12

-module(actor).

-export([loop/0]).

loop() ->

receive

N ->

S = math:sqrt(N),

io:format("sqrt(~p) = ~p~n", [N,S]),

loop()

end.

Friday, February 10, 12

2> Pid = spawn(actor, loop, []).

...

3> Pid ! 4.

sqrt(4) = 2.0

...

5> Pid ! "a".

=ERROR REPORT==== 24-Jan-2012::14:06:02 ===

Error in process <0.40.0>

...

6> is_process_alive(Pid).

false

Friday, February 10, 12

Supervisors

• supervisors monitor processes and take actions on exit signals

• process linking does the trick

Friday, February 10, 12

start() -> spawn(actor, restarter, []).

restarter() ->

process_flag(trap_exit, true),

Pid = spawn_link(actor, loop, []),

register(myActor, Pid),

receive

{'EXIT', _Pid, _Reason} ->

io:format("Process crashed. Restarting~n"),

restarter()

end.

Friday, February 10, 12

2> actor:start().

3> myActor ! 4.

sqrt(4) = 2.0

4> myActor ! "foo".

Process crashed. Restarting

=ERROR REPORT====

Error in process <0.41.0> ...

5> is_process_alive(whereis(myActor)).

true

6> myActor ! 9.

sqrt(9) = 3.0

Friday, February 10, 12

Other great features

• Hot code loading

• OTP Framework

Friday, February 10, 12

Simplicity

• You just learned

• ~70% of Erlang syntax

• most major abstractions: modules, functions and processes

• most of the core data types

Friday, February 10, 12

Complexity

• Erlang/OTP is a complex framework

• Learning it takes time and practice

Friday, February 10, 12

Bad Stuff

• syntax

• Strings

• code organization

• libraries

• underestimated complexity of OTP and concurrent applications generally

• your colleagues will not understand you :)

Friday, February 10, 12

Practical Application

• Notable uses:

• Facebook (Chat)

• CouchDB

• RabbitMQ

• Membase

• Riak

Friday, February 10, 12

How to learn Erlang?

Friday, February 10, 12

http://learnyousomeerlang.com/

Friday, February 10, 12

http://www.erlang.org/doc/getting_started/intro.htmlErlang getting started guide:

Friday, February 10, 12

http://pragprog.com/book/jaerlang/programming-erlang

Programming Erlang: Software for a Concurrent World

Friday, February 10, 12

$ erl

Friday, February 10, 12

[$Q, $u, $e, $s, $t, $i, $o, $n, $s, $?].

Friday, February 10, 12

Thank you

Friday, February 10, 12