Introduction to Erlang
-
Upload
gabriele-lana -
Category
Technology
-
view
4.107 -
download
0
description
Transcript of Introduction to Erlang
Introduction to ErlangGabriele Lana
Why Erlang?
Damien Katz @ Ruby Fringe 2008
Erlang (BEAM) emulator version 5.5.6 [source][smp:1] [async-threads:0] [hipe] [kernel-poll:true]
Eshell V5.5.6 (abort with ^G)1>
Erlang Shell
1> 3.3
2> 1 + 2008.2009
3> 849274893217458392017483921 * 78932489321748392107483291.67035381440116040485849541847226463097212333368664011
Syntax: Number
1> atom.atom
2> anythingStartingWithLowercaseLetter. anythingStartingWithLowercaseLetter
3> 'anything enclosed in single quotes'.'anything enclosed in single quotes'
Syntax: Atom
1> true.true
2> false.false
3> is_atom(true).true
4> is_boolean(true).true
Syntax: Boolean
1> "foo"."foo"
2> "anything enclosed in double quotes"."anything enclosed in double quotes"
Syntax: String
1> [].[]
2> [ 1 ].[1]
3> [ first ].[first]
4> [ "first" ].["first"]
5> [ 1, first, "first" ].[1,first,"first"]
Syntax: List
1> [ 72, 101, 108, 108, 111 ]."Hello"
2> $H.72
3> [ $H, $e, $l, $l, $o ]."Hello"
Syntax: Strings are Lists
1> { 1, 2, 3 }.{1,2,3}
2> { name, "Gabriele" }.{name,"Gabriele"}
3> { coder, { name, "Gabriele" }, { language, "Erlang" } }.{coder,{name,"Gabriele"},{language,"Erlang"}}
Syntax: Tuple
1> 1 = 1.1
2> 1 = 2.** exception error: no match of right hand side value 2
3> catch 1 = 2.{'EXIT',{{badmatch,2},[{erl_eval,expr,3}]}}
Pattern Matching
1> X.* 1: variable 'X' is unbound
2> X = 5.5
3> X.5
4> X = 6.** exception error: no match of right hand side value 6
Pattern Matching: Binding Variables
1> Coder = { coder, { name, "Gabriele" } }.{coder,{name,"Gabriele"}}
2> { person, { name, PersonName } } = Coder.** exception error: no match of right hand side value {coder,{name,"Gabriele"}}
3> { coder, { name, "Gabriele" } } = Coder.{coder,{name,"Gabriele"}}
4> { coder, { name, CoderName } } = Coder. {coder,{name,"Gabriele"}}
Pattern Matching: Destructuring
7> AnotherCoderName = "Matteo"."Matteo"
8> { coder, { name, AnotherCoderName } } = Coder.** exception error: no match of right hand side value {coder,{name,"Gabriele"}}
Pattern Matching: Destructuring
1> [ First, Last ] = [ first, last ].[first,last]
2> First.first
3> Last.last
Pattern Matching: List
4> [ Head | Tail ] = [ 1, 2, 3, 4, 5 ]. [1,2,3,4,5]
5> Head.1
6> Tail.[2,3,4,5]
Pattern Matching: List
1> [ First, Second | Others ] = [ 1, 2, 3, 4, 5 ].[1,2,3,4,5]
2> First.1
3> Second.2
4> Others.[3,4,5]
Pattern Matching: List
1> { X, Y, X } = { { abc, 12 }, 42, { abc, 12 } }.{{abc,12},42,{abc,12}}
2> X.{abc,12}
3> Y.42
Pattern Matching: In Deep
1> { X, Y, X } = { { abc, 12 }, 42, true }.** exception error: no match of right hand side value {{abc,12},42,true}
2> { X, Y, _ } = { { abc, 12 }, 42, true }.{{abc,12},42,true}
Pattern Matching: In Deep
-module(examples).-export([ hello/0 ]).
hello() -> "Hello World!".
1> c(examples).{ok,examples}
2> examples:hello()."Hello World!"
Function
Syntax: Punctuation
• Periods (.) end everything except when
• Semicolons (;) end clauses
• and Commas (,) separate expressions
-export([ double/1 ]).
double(0) -> 0;double(Number) -> Number * 2.
1> examples:double(0).0
2> examples:double(4).8
Function: Pattern Mathing & Clause
double(0) -> 0;double(Number) when is_integer(Number) -> Number * 2.
1> examples:double(4).8
2> examples:double(foo).** exception error: no function clause matching examples:double(foo)
Function: Guard
double(0) -> 0;double(Number) when is_integer(Number) -> Number * 2;double(AnythingElse) -> io:format("I don't know how to double ~p~n", [ AnythingElse ]), error.
1> examples:double(foo).I don't know how to double fooerror
Function: Guard
multiplyBy(Multiplier) -> fun(Number) -> Number * Multiplier end.
1> Double = examples:multiplyBy(2).#Fun<examples.0.46516809>2> Double(4).83> MultiplyBy4 = examples:multiplyBy(4).#Fun<examples.0.46516809>4> MultiplyBy4(4).16
Function: Anonymous & Closure
printList([]) -> ok;printList([ Item | List ]) -> io:format("~p~n", [ Item ]), printList(List).
1> examples:printList([ 1, 2, 3, 4 ]).1234ok
Function: Tail Recursion
foreach(_Function, []) -> ok;foreach(Function, [ Item | List ]) -> Function(Item), foreach(Function, List).
1> examples:foreach(fun(Item) -> io:format("~p~n", [ Item ])end, [ 1, 2, 3, 4 ]).1234
Function: High Order Function
foreach(Function, List) -> lists:foreach(Function, List).
1> examples:foreach(fun(Item) -> io:format("~p~n", [ Item ])end, [ 1, 2, 3, 4 ]).1234ok
Function: High Order Function
3> lists:foreach(fun(Item) -> io:format("~p~n", [ Item ])end, [ 1, 2, 3, 4 ]).1234ok
Function: High Order Function
names(Coders) -> lists:map(fun({ coder, { name, CoderName } }) -> CoderName end, Coders).
1> examples:names([ 1> { coder, { name, "Gabriele" } },1> { coder, { name, "Matteo" } } 1> ]).["Gabriele","Matteo"]
List Functions: Map
triplets(UpTo) when is_number(UpTo), UpTo >= 2 -> [ { A, B, C } || A <- lists:seq(2, UpTo), B <- lists:seq(2, UpTo), C <- lists:seq(2, UpTo), A * A + B * B =:= C * C ].
1> examples:triplets(10).[{3,4,5},{4,3,5},{6,8,10},{8,6,10}]
Syntax: List Comprehension
sum(Numbers) -> lists:foldl(fun(Number, Sum) -> Sum + Number end, 0, Numbers).
1> examples:sum([ 1, 2, 3, 4, 5 ]).15
List Functions: Fold/Reduce
sum(Numbers) -> lists:foldl(fun (Number, Sum) when is_integer(Number) -> Sum + Number; (_Number, Sum) -> Sum end, 0, Numbers).
1> examples:sum([ 1, 2, 3, foo, 4, bar, 5 ]).15
List Functions: Fold/Reduce
fizzbuzz(UpTo) -> lists:map(fun(Counter) -> if (Counter rem 15) =:= 0 -> fizzbuzz; (Counter rem 3) =:= 0 -> fizz; (Counter rem 5) =:= 0 -> buzz; true -> Counter end end, lists:seq(1, UpTo)).
1> examples:fizzbuzz(16).[1,2,fizz,4,buzz,fizz,7,8,fizz,buzz,11,fizz,13,14,fizzbuzz,16]
Example: FizzBuzz
Process: Concurrency
• Any function (named or anonymous) can become a process
• A process is simply a function executing in parallel
• A process shares nothing with other processes• A process is extremely lightweight: a modern
systems can accommodate literally millions of Erlang processes
1> processes:profileSpawnFor(1000). Spawned 1000 processes in 10 (4) millisecondsok
2> processes:profileSpawnFor(10000). Spawned 10000 processes in 40 (96) millisecondsok
3> processes:profileSpawnFor(100000).Spawned 100000 processes in 510 (884) millisecondsok
Process: Concurrency
Process: Concurrency
Process: Concurrency
• The “!” operator sends messages• Asynchronous• Order guaranted
• The “receive” statement matches messages• One call to receive, one message removed
from the process message queue• Uses pattern matching to select messages
1> Pid = spawn(fun() ->1> receive1> die -> io:format("Bye~n")1> end1> end).<0.33.0>
Process: Concurrency
2> is_process_alive(Pid).true
3> Pid ! die.Byedie
4> is_process_alive(Pid).false
Process: Concurrency
profileSpawnFor(Number) -> Processes = for(1, Number, fun() -> spawn(fun() -> wait() end) end), lists:foreach(fun(Pid) -> Pid ! die end, Processes).
wait() -> receive die -> void end.
Process: Concurrency
Process: Fault Tollerance
• The “link” function can link processes• When a process die the linked processes
receive a message { ‘EXIT’, Died, Reason } • A monitor process could respawn the died
ones or cleanup the system
Process: Distributed
• The spawn(Node, Function) can spawn a process in any other known nodes
• No other changes are required!!!
Hard Gained Insights
• Don’t miss tail-call recursion• Asynchronous is good• Small functions are good• When in doubt create a new process• Think early what to do when a process die
Yaws(Yet Another Web Server)
eJabbered(jabber/XMPP)
Disco(Map/Reduce with Erlang + Python)