Erlang Introduction

79
Erlang Introduction Serhiy Oplakanets, Lviv 2012 Friday, February 10, 12

description

 

Transcript of Erlang Introduction

Page 1: Erlang Introduction

Erlang IntroductionSerhiy Oplakanets, Lviv 2012

Friday, February 10, 12

Page 2: Erlang Introduction

Classification

• high-level

• general-purpose

• garbage-collected

• dynamically typed

• functional

• concurrent

Friday, February 10, 12

Page 3: Erlang Introduction

$ 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

Page 4: Erlang Introduction

Syntax

Friday, February 10, 12

Page 5: Erlang Introduction

Data Types

Friday, February 10, 12

Page 6: Erlang Introduction

1> 2 + 2.4

2> 3 * 5.15

3> 7 / 6.1.1666666666666667

Friday, February 10, 12

Page 7: Erlang Introduction

1> [].[]

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

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

Friday, February 10, 12

Page 8: Erlang Introduction

1> "a string"."a string"

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

Friday, February 10, 12

Page 9: Erlang Introduction

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

Friday, February 10, 12

Page 10: Erlang Introduction

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

Friday, February 10, 12

Page 11: Erlang Introduction

1> atom.atom

2> anotherAtom.anotherAtom

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

Friday, February 10, 12

Page 12: Erlang Introduction

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

Friday, February 10, 12

Page 13: Erlang Introduction

1> is_atom(true).true

2> is_atom(false).true

Friday, February 10, 12

Page 14: Erlang Introduction

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

Page 15: Erlang Introduction

Invariable Variables

Friday, February 10, 12

Page 16: Erlang Introduction

1> Variable = "value"."value"

2> AnotherVariable = 128.128

Friday, February 10, 12

Page 17: Erlang Introduction

1> R = 5, Pi = 3.14.3.14

2> Pi.3.14

3> Pi * R * R.78.5

Friday, February 10, 12

Page 18: Erlang Introduction

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

Page 19: Erlang Introduction

Pattern Matching

Friday, February 10, 12

Page 20: Erlang Introduction

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

Friday, February 10, 12

Page 21: Erlang Introduction

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

Friday, February 10, 12

Page 22: Erlang Introduction

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

Friday, February 10, 12

Page 23: Erlang Introduction

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

Friday, February 10, 12

Page 24: Erlang Introduction

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

Page 25: Erlang Introduction

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

Friday, February 10, 12

Page 26: Erlang Introduction

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

Friday, February 10, 12

Page 27: Erlang Introduction

1> _ = 1. 1

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

5> _ = 3.3

Friday, February 10, 12

Page 28: Erlang Introduction

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

2> Head.1

3> Tail.[2,3]

Friday, February 10, 12

Page 29: Erlang Introduction

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

Friday, February 10, 12

Page 30: Erlang Introduction

Modules and Functions

Friday, February 10, 12

Page 31: Erlang Introduction

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

main() -> "Hello".

Friday, February 10, 12

Page 32: Erlang Introduction

1> test:main()."Hello"

Friday, February 10, 12

Page 33: Erlang Introduction

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

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

Friday, February 10, 12

Page 34: Erlang Introduction

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

Friday, February 10, 12

Page 35: Erlang Introduction

-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

Page 36: Erlang Introduction

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

Friday, February 10, 12

Page 37: Erlang Introduction

Function Guards

Friday, February 10, 12

Page 38: Erlang Introduction

-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

Page 39: Erlang Introduction

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

Page 40: Erlang Introduction

% 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

Page 41: Erlang Introduction

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

Page 42: Erlang Introduction

Concurrency

• any function can become a process

• process is a function executing in parallel

• process shares nothing with other processes

Friday, February 10, 12

Page 43: Erlang Introduction

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

Page 44: Erlang Introduction

spawn(Module, Function, Arguments) -> Pid

Friday, February 10, 12

Page 45: Erlang Introduction

Any function can become a process

Friday, February 10, 12

Page 46: Erlang Introduction

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

Hello

...

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

Hello

...

Friday, February 10, 12

Page 47: Erlang Introduction

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

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

Friday, February 10, 12

Page 48: Erlang Introduction

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

Page 49: Erlang Introduction

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

Friday, February 10, 12

Page 50: Erlang Introduction

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

Page 51: Erlang Introduction

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

Friday, February 10, 12

Page 52: Erlang Introduction

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

Page 53: Erlang Introduction

Processes are executed in parallel and share no

data

Friday, February 10, 12

Page 54: Erlang Introduction

-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

Page 55: Erlang Introduction

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

Page 56: Erlang Introduction

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

Page 57: Erlang Introduction

Distributed Erlang

Friday, February 10, 12

Page 58: Erlang Introduction

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

Friday, February 10, 12

Page 59: Erlang Introduction

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

Friday, February 10, 12

Page 60: Erlang Introduction

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

...

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

'slave@Serhiys-MacBook-Pro'

Friday, February 10, 12

Page 61: Erlang Introduction

$ 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

Page 62: Erlang Introduction

Fault Tolerance

Friday, February 10, 12

Page 63: Erlang Introduction

-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

Page 64: Erlang Introduction

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

Page 65: Erlang Introduction

Supervisors

• supervisors monitor processes and take actions on exit signals

• process linking does the trick

Friday, February 10, 12

Page 66: Erlang Introduction

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

Page 67: Erlang Introduction

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

Page 68: Erlang Introduction

Other great features

• Hot code loading

• OTP Framework

Friday, February 10, 12

Page 69: Erlang Introduction

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

Page 70: Erlang Introduction

Complexity

• Erlang/OTP is a complex framework

• Learning it takes time and practice

Friday, February 10, 12

Page 71: Erlang Introduction

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

Page 72: Erlang Introduction

Practical Application

• Notable uses:

• Facebook (Chat)

• CouchDB

• RabbitMQ

• Membase

• Riak

Friday, February 10, 12

Page 73: Erlang Introduction

How to learn Erlang?

Friday, February 10, 12

Page 74: Erlang Introduction

http://learnyousomeerlang.com/

Friday, February 10, 12

Page 75: Erlang Introduction

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

Friday, February 10, 12

Page 76: Erlang Introduction

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

Programming Erlang: Software for a Concurrent World

Friday, February 10, 12

Page 77: Erlang Introduction

$ erl

Friday, February 10, 12

Page 78: Erlang Introduction

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

Friday, February 10, 12

Page 79: Erlang Introduction

Thank you

Friday, February 10, 12