LEARN U ERLANG
WEEK-2 PRESENTED BY NOLLEH
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ greet without patten matching
function greet(Gender,Name)
if Gender == male then
print("Hello, Mr. %s!", Name)
else if Gender == female then
print("Hello, Mrs. %s!", Name)
else
print("Hello, %s!", Name)
end
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ greet with patten matching
greet(male, Name) ->
io:format("Hello, Mr. ~s!", [Name]);
greet(female, Name) ->
io:format("Hello, Mrs. ~s!", [Name]);
greet(_, Name) ->
io:format("Hello, ~s!", [Name]).
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ disusing / using
function(X) ->
Expression;
function(Y) ->
Expression;
function(_) ->
Expression.
function(Args)
if X then
Expression
else if Y then
Expression
else
Expression
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ example
head([H|_]) -> H.
second([_,X|_]) -> X.
same(X,X) ->
true;
same(_,_) ->
false.
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ how’s it works?
▸ error occurs unless the new value is the same as the old
one
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ example2
▸ functions head’s ‘=‘ operator
valid_time({Date = {Y,M,D}, Time = {H,Min,S}}) ->
io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n”,
[Date,Y,M,D]),
io:format("The time tuple (~p) indicates: ~p:~p:~p.~n”,
[Time,H,Min,S]);
valid_time(_) ->
io:format("Stop feeding me wrong data!~n").
3. SYNTAX IN FUNCTIONS
PATTERN MATCHING
▸ example2
▸ prob: It also recv just tuple! and too precise sometimes.
4> c(functions).
{ok, functions}
5> functions:valid_time({{2011,09,06},{09,04,43}}).
The Date tuple ({2011,9,6}) says today is: 2011/9/6,
The time tuple ({9,4,43}) indicates: 9:4:43.
ok
6> functions:valid_time({{2011,09,06},{09,04}}).
Stop feeding me wrong data!
3. SYNTAX IN FUNCTIONS
GUARDS,GUARDS!
▸ needs expressive way on sometimes…
▸ range of value
▸ not limited as certain types of data
3. SYNTAX IN FUNCTIONS
GUARDS,GUARDS!
▸ impractical vs practical
old_enough(0) -> false;
old_enough(1) -> false;
old_enough(2) -> false;
...
old_enough(14) -> false;
old_enough(15) -> false;
old_enough(_) -> true.
ok
old_enough(X) when X >= 16 -> true;
old_enough(_) -> false.
3. SYNTAX IN FUNCTIONS
GUARDS,GUARDS!
▸ simillar with andalso (little diff aspect on exceptions)
▸ orelse
right_age(X) when X >= 16, X =< 104 ->
true;
right_age(_) ->
false.
wrong_age(X) when X < 16; X > 104 ->
true;
wrong_age(_) ->
false.
3. SYNTAX IN FUNCTIONS
GUARDS,GUARDS!
▸ in guard, You will be
▸ able to use functions like
▸ A*B/C >= 0
▸ is_integer/1, is_atom/1 …
▸ unable to use user defined function
▸ because of side-effect
3. SYNTAX IN FUNCTIONS
WHAT THE IF!?
▸ similiar with guard but outside of function clauses head
▸ different from other language
3. SYNTAX IN FUNCTIONS
WHAT THE IF!?
-module(what_the_if).
-export([heh_fine/0]).
heh_fine() ->
if 1 =:= 1 ->
works
end,
if 1 =:= 2; 1 =:= 1 ->
works
end,
if 1 =:= 2, 1 =:= 1 ->
fails
end.
3. SYNTAX IN FUNCTIONS
WHAT THE IF!?
1> c(what_the_if).
./what_the_if.erl:12: Warning: no clause will ever match
./what_the_if.erl:12: Warning: the guard for this clause evaluates to
'false'
{ok,what_the_if}
2> what_the_if:heh_fine().
** exception error: no true branch found when evaluating an if
expression
in function what_the_if:heh_fine/0
3. SYNTAX IN FUNCTIONS
WHAT THE IF!?
▸ true branch
oh_god(N) ->
if N =:= 2 -> might_succeed;
true -> always_does %% this is Erlang's if's 'else!'
end.
4> what_the_if:oh_god(2).
might_succeed
5> what_the_if:oh_god(3).
always_does
3. SYNTAX IN FUNCTIONS
WHAT IS IF!?
▸ why not else ?
▸ both branch should be avoided
▸ if is usually easier
▸ guard has only limited set
3. SYNTAX IN FUNCTIONS
IN CASE … OF
▸ example
insert(X,[]) ->
[X];
insert(X,Set) ->
case lists:member(X,Set) of
true -> Set;
false -> [X|Set]
end.
3. SYNTAX IN FUNCTIONS
IN CASE … OF
▸ pattern matching + guard
beach(Temperature) ->
case Temperature of
{celsius, N} when N >= 20, N =< 45 ->
'favorable';
{kelvin, N} when N >= 293, N =< 318 ->
'scientifically favorable';
{fahrenheit, N} when N >= 68, N =< 113 ->
'favorable in the US’;
_ ->
'avoid beach'
end.
3. SYNTAX IN FUNCTIONS
IN CASE … OF
▸ instead, we can replace with bunch of functions.
beachf({celsius, N}) when N >= 20, N =< 45 ->
'favorable';
...
beachf(_) ->
'avoid beach'.
3. SYNTAX IN FUNCTIONS
WHICH TO USE?
▸ function call vs case of
▸ same way at a lower level
▸ only one difference when arg is more than one
case {A,B} of
Pattern Guards -> ...
end.
3. SYNTAX IN FUNCTIONS
WHICH TO USE?
▸ function call vs case of
▸ arguably cleaner
insert(X,[]) ->
[X];
insert(X,Set) ->
case lists:member(X,Set) of
true -> Set;
false -> [X|Set]
end.
3. SYNTAX IN FUNCTIONS
WHICH TO USE?
▸ if vs if through guard?
▸ use where doesn’t need whole pattern matching
▸ personal preference
4. TYPES (OR LACK OF THERE OF)
DYNAMITE-STRONG TYPING
▸ as you’ve seen, no need to type Type!
▸ elang is dynamically typed
▸ compiler won't always yell at you
▸ statically typed language is safer..?
▸ elang is reported as nine nine (99.999 % available)
▸ strongly typed
1> 6 + "1".
4. TYPES (OR LACK OF THERE OF)
DYNAMITE-STRONG TYPING
▸ type conversion
<type>_to_<type>
1> erlang:list_to_integer("54").
54
2> erlang:integer_to_list(54).
"54"
3> erlang:list_to_integer("54.32").
** exception error: bad argument in function list_to_integer/1
called as list_to_integer("54.32")
4. TYPES (OR LACK OF THERE OF)
TYPE CONVERSION
▸ type conversion
<type>_to_<type>
4> erlang:list_to_float("54.32").
54.32
5> erlang:atom_to_list(true).
"true"
6> erlang:list_to_bitstring("hi there").
<<"hi there">>
7> erlang:bitstring_to_list(<<"hi there">>).
"hi there"
4. TYPES (OR LACK OF THERE OF)
TO GUARD A DATA TYPE
▸ type check
▸ why not typeof
▸ force user to make program that surely knowing the effect
▸ can used in guard expression
is_atom/1 is_binary/1
is_bitstring/1 is_boolean/1 is_builtin/3
is_float/1 is_function/1 is_function/2
is_integer/1 is_list/1 is_number/1
is_pid/1 is_port/1 is_record/2
is_record/3 is_reference/1 is_tuple/1
4. TYPES (OR LACK OF THERE OF)
FOR TYPE JUNKIES
▸ briefly describe tools used to do static type analysis
▸ first try in 1997
▸ success type
▸ will not exact type every expression
▸ type it infers are right, type errors it finds are really error
4. TYPES (OR LACK OF THERE OF)
FOR TYPE JUNKIES
▸ success type
and(_,_) -> bool()
and(false, _) -> false;
and(_, false) -> false;
and(true,true) -> true.
4. TYPES (OR LACK OF THERE OF)
FOR TYPE JUNKIES
▸ if you interested
$ typer --help
$ dialyzer --help
5. RECURSION
HELLO RECURSION!
▸ functional programming do not offer loop
5. RECURSION
HELLO RECURSION!
▸ factorial
-module(recursive).
-export([fac/1]).
fac(N) when N == 0 -> 1;
fac(N) when N > 0 -> N*fac(N-1).
fac(0) -> 1;
fac(N) when N > 0 -> N*fac(N-1).
5. RECURSION
HELLO RECURSION!
▸ recursion
▸ function that calls itself
▸ need to have stopping condition (base case)
5. RECURSION
LENGTH
▸ we need
▸ simplest - empty list
a base case;
a function that calls itself;
a list to try our function on.
fac(0) -> 1;
fac(N) when N > 0 -> N*fac(N-1).
5, RECURSION
LENGTH
▸ list is recursively
[1 | [2| ... [n | []]]].
len([]) -> 0;
len([_|T]) -> 1 + len(T).
5, RECURSION
LENGTH
▸ how it works?
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
5. RECURSION
LENGTH OF A TAIL RECURSION
▸ it is problematic
▸ keep millions of numbers in memory for such a simple
calculation.
▸ let’s tail recursion
5. RECURSION
LENGTH OF A TAIL RECURSION
▸ linear -> iterative one
▸ need to be alone
▸ additional is stacked
▸ accumulator
▸ need to extra variable to hold the intermediate result
5. RECURSION
LENGTH OF A TAIL RECURSION
▸ using accumulator
tail_fac(N) -> tail_fac(N,1).
tail_fac(0,Acc) -> Acc;
tail_fac(N,Acc) when N > 0 -> tail_fac(N-1,N*Acc).
tail_fac(4) = tail_fac(4,1)
tail_fac(4,1) = tail_fac(4-1, 4*1)
tail_fac(3,4) = tail_fac(3-1, 3*4)
tail_fac(2,12) = tail_fac(2-1, 2*12)
tail_fac(1,24) = tail_fac(1-1, 1*24)
tail_fac(0,24) = 24
5. RECURSION
LENGTH OF A TAIL RECURSION
▸ length tail recursion
tail_len(L) -> tail_len(L,0).
tail_len([], Acc) -> Acc;
tail_len([_|T], Acc) -> tail_len(T,Acc+1).
len([]) -> 0;
len([_|T]) -> 1 + len(T).
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ After all, recursion being the only looping construct that
exists in Erlang
▸ except list comprehension
▸ duplicate
duplicate(0,_) ->
[];
duplicate(N,Term) when N > 0 ->
[Term|duplicate(N-1,Term)].
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ duplicate
tail_duplicate(N,Term) ->
tail_duplicate(N,Term,[]).
tail_duplicate(0,_,List) ->
List;
tail_duplicate(N,Term,List) when N > 0 ->
tail_duplicate(N-1, Term, [Term|List]).
function(N, Term) ->
while N > 0 ->
List = [Term|List],
N = N-1
end,
List.
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ true nightmare which is not tail recursion
reverse([]) -> [];
reverse([H|T]) -> reverse(T)++[H].
reverse([1,2,3,4]) = [4]++[3]++[2]++[1]
↑ ↵
= [4,3]++[2]++[1]
↑ ↑ ↵
= [4,3,2]++[1]
↑ ↑ ↑ ↵
= [4,3,2,1]
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ let’s rescue
tail_reverse(L) -> tail_reverse(L,[]).
tail_reverse([],Acc) -> Acc;
tail_reverse([H|T],Acc) -> tail_reverse(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]
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ sublist/2
▸ a little different
sublist(_,0) -> [];
sublist([],_) -> [];
sublist([H|T],N) when N > 0 -> [H|sublist(T,N-1)].
tail_sublist(L, N) -> tail_sublist(L, N, []).
tail_sublist(_, 0, SubList) -> SubList;
tail_sublist([], _, SubList) -> SubList;
tail_sublist([H|T], N, SubList) when N > 0 ->
tail_sublist(T, N-1, [H|SubList]).
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ problems..
▸ solve
sublist([1,2,3,4,5,6],3)
tail_sublist(L, N) -> reverse(tail_sublist(L, N, [])).
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ zip/2
▸ implements
1> recursive:zip([a,b,c],[1,2,3]).
[{a,1},{b,2},{c,3}]
zip([],[]) -> [];
zip([X|Xs],[Y|Ys]) -> [{X,Y}|zip(Xs,Ys)].
lenient_zip([],_) -> [];
lenient_zip(_,[]) -> [];
lenient_zip([X|Xs],[Y|Ys]) -> [{X,Y}|lenient_zip(Xs,Ys)].
5. RECURSION
MORE RECURSIVE FUNCTIONS
▸ TCO (tail call optimization)
▸ vm does eliminate current stack frame
▸ LCO (last call optimization)
▸ more general
5. RECURSION
QUICK, SORT!
▸ naive version
▸ pivot
▸ smallers; equals | lagers
▸ until empty list to sort
5. RECURSION
QUICK, SORT!
▸ naive version
5. RECURSION
QUICK, SORT!
▸ as two parts
▸ partioning
▸ apply the partitioning to each parts, and glue
quicksort([]) -> [];
quicksort([Pivot|Rest]) ->
{Smaller, Larger} = partition(Pivot,Rest,[],[]),
quicksort(Smaller) ++ [Pivot] ++ quicksort(Larger).
5. RECURSION
QUICK, SORT!
▸ partitioning
partition(_,[], Smaller, Larger) -> {Smaller, Larger};
partition(Pivot, [H|T], Smaller, Larger) ->
if H =< Pivot -> partition(Pivot, T, [H|Smaller], Larger);
H > Pivot -> partition(Pivot, T, Smaller, [H|Larger])
end.
lc_quicksort([]) -> [];
lc_quicksort([Pivot|Rest]) ->
lc_quicksort([Smaller || Smaller <- Rest, Smaller =< Pivot])
++ [Pivot] ++
lc_quicksort([Larger || Larger <- Rest, Larger > Pivot]).
5. RECURSION
MORE THAN LISTS
▸ tree
▸ key / two other node (smaller, larger)
▸ also able to contain empty node
5. RECURSION
MORE THAN LISTS
▸ lets choice tuple!
▸ empty
{node, {Key, Value, Smaller, Larger}}
{node, nil}
-module(tree).
-export([empty/0, insert/3, lookup/2]).
empty() -> {node, 'nil'}.
5. RECURSION
MORE THAN LISTS
▸ base case is empty node
▸ where to put content
▸ compare, larger / smaller
5. RECURSION
MORE THAN LISTS
▸ compare, larger / smaller
insert(Key, Val, {node, 'nil'}) ->
{node, {Key, Val, {node, 'nil'}, {node, 'nil'}}};
insert(NewKey, NewVal, {node, {Key, Val, Smaller, Larger}})
when NewKey < Key ->
{node, {Key, Val, insert(NewKey, NewVal, Smaller), Larger}};
insert(NewKey, NewVal, {node, {Key, Val, Smaller, Larger}})
when NewKey > Key ->
{node, {Key, Val, Smaller, insert(NewKey, NewVal, Larger)}};
insert(Key, Val, {node, {Key, _, Smaller, Larger}}) ->
{node, {Key, Val, Smaller, Larger}}.
5. RECURSION
MORE THAN LISTS
▸ returns completely new tree
▸ sometimes shared by vm
▸ look up
lookup(_, {node, 'nil'}) ->
undefined;
lookup(Key, {node, {Key, Val, _, _}}) ->
{ok, Val};
lookup(Key, {node, {NodeKey, _, Smaller, _}}) when Key < NodeKey ->
lookup(Key, Smaller);
lookup(Key, {node, {_, _, _, Larger}}) -> lookup(Key, Larger).
▸ using example
5. RECURSION
MORE THAN LISTS
1> T1 = tree:insert("Jim Woodland", "jim.woodland@gmail.com",
tree:empty()).
2> T2 = tree:insert("Mark Anderson", "i.am.a@hotmail.com", T1).
3> Addresses = tree:insert("Anita Bath", “abath@someuni.edu",
tree:insert("Kevin Robert", "myfairy@yahoo.com",
tree:insert(“Wilson Longbrow", "longwil@gmail.com", T2))).
5. RECURSION
MORE THAN LISTS
{node,{"Jim Woodland","jim.woodland@gmail.com",
{node,{"Anita Bath","abath@someuni.edu",
{node,nil},
{node,nil}}},
{node,{"Mark Anderson","i.am.a@hotmail.com",
{node,{"Kevin Robert","myfairy@yahoo.com",
{node,nil},
{node,nil}}},
{node,{"Wilson Longbrow","longwil@gmail.com",
{node,nil},
{node,nil}}}}}}}
5. RECURSION
MORE THAN LISTS
▸ using example
4> tree:lookup("Anita Bath", Addresses).
{ok, "abath@someuni.edu"}
5> tree:lookup("Jacques Requin", Addresses).
undefined
5. RECURSION
THINKING RECURSIVELY
▸ our approach is more declarative
▸ consise algorithm easy to understand
▸ divide - and - conquer!
▸ you will learn how to abstract, next time.

learn you some erlang - chap3 to chap5

  • 1.
    LEARN U ERLANG WEEK-2PRESENTED BY NOLLEH
  • 2.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ greet without patten matching function greet(Gender,Name) if Gender == male then print("Hello, Mr. %s!", Name) else if Gender == female then print("Hello, Mrs. %s!", Name) else print("Hello, %s!", Name) end
  • 3.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ greet with patten matching greet(male, Name) -> io:format("Hello, Mr. ~s!", [Name]); greet(female, Name) -> io:format("Hello, Mrs. ~s!", [Name]); greet(_, Name) -> io:format("Hello, ~s!", [Name]).
  • 4.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ disusing / using function(X) -> Expression; function(Y) -> Expression; function(_) -> Expression. function(Args) if X then Expression else if Y then Expression else Expression
  • 5.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ example head([H|_]) -> H. second([_,X|_]) -> X. same(X,X) -> true; same(_,_) -> false.
  • 6.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ how’s it works? ▸ error occurs unless the new value is the same as the old one
  • 7.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ example2 ▸ functions head’s ‘=‘ operator valid_time({Date = {Y,M,D}, Time = {H,Min,S}}) -> io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n”, [Date,Y,M,D]), io:format("The time tuple (~p) indicates: ~p:~p:~p.~n”, [Time,H,Min,S]); valid_time(_) -> io:format("Stop feeding me wrong data!~n").
  • 8.
    3. SYNTAX INFUNCTIONS PATTERN MATCHING ▸ example2 ▸ prob: It also recv just tuple! and too precise sometimes. 4> c(functions). {ok, functions} 5> functions:valid_time({{2011,09,06},{09,04,43}}). The Date tuple ({2011,9,6}) says today is: 2011/9/6, The time tuple ({9,4,43}) indicates: 9:4:43. ok 6> functions:valid_time({{2011,09,06},{09,04}}). Stop feeding me wrong data!
  • 9.
    3. SYNTAX INFUNCTIONS GUARDS,GUARDS! ▸ needs expressive way on sometimes… ▸ range of value ▸ not limited as certain types of data
  • 10.
    3. SYNTAX INFUNCTIONS GUARDS,GUARDS! ▸ impractical vs practical old_enough(0) -> false; old_enough(1) -> false; old_enough(2) -> false; ... old_enough(14) -> false; old_enough(15) -> false; old_enough(_) -> true. ok old_enough(X) when X >= 16 -> true; old_enough(_) -> false.
  • 11.
    3. SYNTAX INFUNCTIONS GUARDS,GUARDS! ▸ simillar with andalso (little diff aspect on exceptions) ▸ orelse right_age(X) when X >= 16, X =< 104 -> true; right_age(_) -> false. wrong_age(X) when X < 16; X > 104 -> true; wrong_age(_) -> false.
  • 12.
    3. SYNTAX INFUNCTIONS GUARDS,GUARDS! ▸ in guard, You will be ▸ able to use functions like ▸ A*B/C >= 0 ▸ is_integer/1, is_atom/1 … ▸ unable to use user defined function ▸ because of side-effect
  • 13.
    3. SYNTAX INFUNCTIONS WHAT THE IF!? ▸ similiar with guard but outside of function clauses head ▸ different from other language
  • 14.
    3. SYNTAX INFUNCTIONS WHAT THE IF!? -module(what_the_if). -export([heh_fine/0]). heh_fine() -> if 1 =:= 1 -> works end, if 1 =:= 2; 1 =:= 1 -> works end, if 1 =:= 2, 1 =:= 1 -> fails end.
  • 15.
    3. SYNTAX INFUNCTIONS WHAT THE IF!? 1> c(what_the_if). ./what_the_if.erl:12: Warning: no clause will ever match ./what_the_if.erl:12: Warning: the guard for this clause evaluates to 'false' {ok,what_the_if} 2> what_the_if:heh_fine(). ** exception error: no true branch found when evaluating an if expression in function what_the_if:heh_fine/0
  • 16.
    3. SYNTAX INFUNCTIONS WHAT THE IF!? ▸ true branch oh_god(N) -> if N =:= 2 -> might_succeed; true -> always_does %% this is Erlang's if's 'else!' end. 4> what_the_if:oh_god(2). might_succeed 5> what_the_if:oh_god(3). always_does
  • 17.
    3. SYNTAX INFUNCTIONS WHAT IS IF!? ▸ why not else ? ▸ both branch should be avoided ▸ if is usually easier ▸ guard has only limited set
  • 18.
    3. SYNTAX INFUNCTIONS IN CASE … OF ▸ example insert(X,[]) -> [X]; insert(X,Set) -> case lists:member(X,Set) of true -> Set; false -> [X|Set] end.
  • 19.
    3. SYNTAX INFUNCTIONS IN CASE … OF ▸ pattern matching + guard beach(Temperature) -> case Temperature of {celsius, N} when N >= 20, N =< 45 -> 'favorable'; {kelvin, N} when N >= 293, N =< 318 -> 'scientifically favorable'; {fahrenheit, N} when N >= 68, N =< 113 -> 'favorable in the US’; _ -> 'avoid beach' end.
  • 20.
    3. SYNTAX INFUNCTIONS IN CASE … OF ▸ instead, we can replace with bunch of functions. beachf({celsius, N}) when N >= 20, N =< 45 -> 'favorable'; ... beachf(_) -> 'avoid beach'.
  • 21.
    3. SYNTAX INFUNCTIONS WHICH TO USE? ▸ function call vs case of ▸ same way at a lower level ▸ only one difference when arg is more than one case {A,B} of Pattern Guards -> ... end.
  • 22.
    3. SYNTAX INFUNCTIONS WHICH TO USE? ▸ function call vs case of ▸ arguably cleaner insert(X,[]) -> [X]; insert(X,Set) -> case lists:member(X,Set) of true -> Set; false -> [X|Set] end.
  • 23.
    3. SYNTAX INFUNCTIONS WHICH TO USE? ▸ if vs if through guard? ▸ use where doesn’t need whole pattern matching ▸ personal preference
  • 24.
    4. TYPES (ORLACK OF THERE OF) DYNAMITE-STRONG TYPING ▸ as you’ve seen, no need to type Type! ▸ elang is dynamically typed ▸ compiler won't always yell at you ▸ statically typed language is safer..? ▸ elang is reported as nine nine (99.999 % available) ▸ strongly typed 1> 6 + "1".
  • 25.
    4. TYPES (ORLACK OF THERE OF) DYNAMITE-STRONG TYPING ▸ type conversion <type>_to_<type> 1> erlang:list_to_integer("54"). 54 2> erlang:integer_to_list(54). "54" 3> erlang:list_to_integer("54.32"). ** exception error: bad argument in function list_to_integer/1 called as list_to_integer("54.32")
  • 26.
    4. TYPES (ORLACK OF THERE OF) TYPE CONVERSION ▸ type conversion <type>_to_<type> 4> erlang:list_to_float("54.32"). 54.32 5> erlang:atom_to_list(true). "true" 6> erlang:list_to_bitstring("hi there"). <<"hi there">> 7> erlang:bitstring_to_list(<<"hi there">>). "hi there"
  • 27.
    4. TYPES (ORLACK OF THERE OF) TO GUARD A DATA TYPE ▸ type check ▸ why not typeof ▸ force user to make program that surely knowing the effect ▸ can used in guard expression is_atom/1 is_binary/1 is_bitstring/1 is_boolean/1 is_builtin/3 is_float/1 is_function/1 is_function/2 is_integer/1 is_list/1 is_number/1 is_pid/1 is_port/1 is_record/2 is_record/3 is_reference/1 is_tuple/1
  • 28.
    4. TYPES (ORLACK OF THERE OF) FOR TYPE JUNKIES ▸ briefly describe tools used to do static type analysis ▸ first try in 1997 ▸ success type ▸ will not exact type every expression ▸ type it infers are right, type errors it finds are really error
  • 29.
    4. TYPES (ORLACK OF THERE OF) FOR TYPE JUNKIES ▸ success type and(_,_) -> bool() and(false, _) -> false; and(_, false) -> false; and(true,true) -> true.
  • 30.
    4. TYPES (ORLACK OF THERE OF) FOR TYPE JUNKIES ▸ if you interested $ typer --help $ dialyzer --help
  • 31.
    5. RECURSION HELLO RECURSION! ▸functional programming do not offer loop
  • 32.
    5. RECURSION HELLO RECURSION! ▸factorial -module(recursive). -export([fac/1]). fac(N) when N == 0 -> 1; fac(N) when N > 0 -> N*fac(N-1). fac(0) -> 1; fac(N) when N > 0 -> N*fac(N-1).
  • 33.
    5. RECURSION HELLO RECURSION! ▸recursion ▸ function that calls itself ▸ need to have stopping condition (base case)
  • 34.
    5. RECURSION LENGTH ▸ weneed ▸ simplest - empty list a base case; a function that calls itself; a list to try our function on. fac(0) -> 1; fac(N) when N > 0 -> N*fac(N-1).
  • 35.
    5, RECURSION LENGTH ▸ listis recursively [1 | [2| ... [n | []]]]. len([]) -> 0; len([_|T]) -> 1 + len(T).
  • 36.
    5, RECURSION LENGTH ▸ howit works? 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
  • 37.
    5. RECURSION LENGTH OFA TAIL RECURSION ▸ it is problematic ▸ keep millions of numbers in memory for such a simple calculation. ▸ let’s tail recursion
  • 38.
    5. RECURSION LENGTH OFA TAIL RECURSION ▸ linear -> iterative one ▸ need to be alone ▸ additional is stacked ▸ accumulator ▸ need to extra variable to hold the intermediate result
  • 39.
    5. RECURSION LENGTH OFA TAIL RECURSION ▸ using accumulator tail_fac(N) -> tail_fac(N,1). tail_fac(0,Acc) -> Acc; tail_fac(N,Acc) when N > 0 -> tail_fac(N-1,N*Acc). tail_fac(4) = tail_fac(4,1) tail_fac(4,1) = tail_fac(4-1, 4*1) tail_fac(3,4) = tail_fac(3-1, 3*4) tail_fac(2,12) = tail_fac(2-1, 2*12) tail_fac(1,24) = tail_fac(1-1, 1*24) tail_fac(0,24) = 24
  • 40.
    5. RECURSION LENGTH OFA TAIL RECURSION ▸ length tail recursion tail_len(L) -> tail_len(L,0). tail_len([], Acc) -> Acc; tail_len([_|T], Acc) -> tail_len(T,Acc+1). len([]) -> 0; len([_|T]) -> 1 + len(T).
  • 41.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ After all, recursion being the only looping construct that exists in Erlang ▸ except list comprehension ▸ duplicate duplicate(0,_) -> []; duplicate(N,Term) when N > 0 -> [Term|duplicate(N-1,Term)].
  • 42.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ duplicate tail_duplicate(N,Term) -> tail_duplicate(N,Term,[]). tail_duplicate(0,_,List) -> List; tail_duplicate(N,Term,List) when N > 0 -> tail_duplicate(N-1, Term, [Term|List]). function(N, Term) -> while N > 0 -> List = [Term|List], N = N-1 end, List.
  • 43.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ true nightmare which is not tail recursion reverse([]) -> []; reverse([H|T]) -> reverse(T)++[H]. reverse([1,2,3,4]) = [4]++[3]++[2]++[1] ↑ ↵ = [4,3]++[2]++[1] ↑ ↑ ↵ = [4,3,2]++[1] ↑ ↑ ↑ ↵ = [4,3,2,1]
  • 44.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ let’s rescue tail_reverse(L) -> tail_reverse(L,[]). tail_reverse([],Acc) -> Acc; tail_reverse([H|T],Acc) -> tail_reverse(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]
  • 45.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ sublist/2 ▸ a little different sublist(_,0) -> []; sublist([],_) -> []; sublist([H|T],N) when N > 0 -> [H|sublist(T,N-1)]. tail_sublist(L, N) -> tail_sublist(L, N, []). tail_sublist(_, 0, SubList) -> SubList; tail_sublist([], _, SubList) -> SubList; tail_sublist([H|T], N, SubList) when N > 0 -> tail_sublist(T, N-1, [H|SubList]).
  • 46.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ problems.. ▸ solve sublist([1,2,3,4,5,6],3) tail_sublist(L, N) -> reverse(tail_sublist(L, N, [])).
  • 47.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ zip/2 ▸ implements 1> recursive:zip([a,b,c],[1,2,3]). [{a,1},{b,2},{c,3}] zip([],[]) -> []; zip([X|Xs],[Y|Ys]) -> [{X,Y}|zip(Xs,Ys)]. lenient_zip([],_) -> []; lenient_zip(_,[]) -> []; lenient_zip([X|Xs],[Y|Ys]) -> [{X,Y}|lenient_zip(Xs,Ys)].
  • 48.
    5. RECURSION MORE RECURSIVEFUNCTIONS ▸ TCO (tail call optimization) ▸ vm does eliminate current stack frame ▸ LCO (last call optimization) ▸ more general
  • 49.
    5. RECURSION QUICK, SORT! ▸naive version ▸ pivot ▸ smallers; equals | lagers ▸ until empty list to sort
  • 50.
  • 51.
    5. RECURSION QUICK, SORT! ▸as two parts ▸ partioning ▸ apply the partitioning to each parts, and glue quicksort([]) -> []; quicksort([Pivot|Rest]) -> {Smaller, Larger} = partition(Pivot,Rest,[],[]), quicksort(Smaller) ++ [Pivot] ++ quicksort(Larger).
  • 52.
    5. RECURSION QUICK, SORT! ▸partitioning partition(_,[], Smaller, Larger) -> {Smaller, Larger}; partition(Pivot, [H|T], Smaller, Larger) -> if H =< Pivot -> partition(Pivot, T, [H|Smaller], Larger); H > Pivot -> partition(Pivot, T, Smaller, [H|Larger]) end. lc_quicksort([]) -> []; lc_quicksort([Pivot|Rest]) -> lc_quicksort([Smaller || Smaller <- Rest, Smaller =< Pivot]) ++ [Pivot] ++ lc_quicksort([Larger || Larger <- Rest, Larger > Pivot]).
  • 53.
    5. RECURSION MORE THANLISTS ▸ tree ▸ key / two other node (smaller, larger) ▸ also able to contain empty node
  • 54.
    5. RECURSION MORE THANLISTS ▸ lets choice tuple! ▸ empty {node, {Key, Value, Smaller, Larger}} {node, nil} -module(tree). -export([empty/0, insert/3, lookup/2]). empty() -> {node, 'nil'}.
  • 55.
    5. RECURSION MORE THANLISTS ▸ base case is empty node ▸ where to put content ▸ compare, larger / smaller
  • 56.
    5. RECURSION MORE THANLISTS ▸ compare, larger / smaller insert(Key, Val, {node, 'nil'}) -> {node, {Key, Val, {node, 'nil'}, {node, 'nil'}}}; insert(NewKey, NewVal, {node, {Key, Val, Smaller, Larger}}) when NewKey < Key -> {node, {Key, Val, insert(NewKey, NewVal, Smaller), Larger}}; insert(NewKey, NewVal, {node, {Key, Val, Smaller, Larger}}) when NewKey > Key -> {node, {Key, Val, Smaller, insert(NewKey, NewVal, Larger)}}; insert(Key, Val, {node, {Key, _, Smaller, Larger}}) -> {node, {Key, Val, Smaller, Larger}}.
  • 57.
    5. RECURSION MORE THANLISTS ▸ returns completely new tree ▸ sometimes shared by vm ▸ look up lookup(_, {node, 'nil'}) -> undefined; lookup(Key, {node, {Key, Val, _, _}}) -> {ok, Val}; lookup(Key, {node, {NodeKey, _, Smaller, _}}) when Key < NodeKey -> lookup(Key, Smaller); lookup(Key, {node, {_, _, _, Larger}}) -> lookup(Key, Larger).
  • 58.
    ▸ using example 5.RECURSION MORE THAN LISTS 1> T1 = tree:insert("Jim Woodland", "[email protected]", tree:empty()). 2> T2 = tree:insert("Mark Anderson", "[email protected]", T1). 3> Addresses = tree:insert("Anita Bath", “[email protected]", tree:insert("Kevin Robert", "[email protected]", tree:insert(“Wilson Longbrow", "[email protected]", T2))).
  • 59.
    5. RECURSION MORE THANLISTS {node,{"Jim Woodland","[email protected]", {node,{"Anita Bath","[email protected]", {node,nil}, {node,nil}}}, {node,{"Mark Anderson","[email protected]", {node,{"Kevin Robert","[email protected]", {node,nil}, {node,nil}}}, {node,{"Wilson Longbrow","[email protected]", {node,nil}, {node,nil}}}}}}}
  • 60.
    5. RECURSION MORE THANLISTS ▸ using example 4> tree:lookup("Anita Bath", Addresses). {ok, "[email protected]"} 5> tree:lookup("Jacques Requin", Addresses). undefined
  • 61.
    5. RECURSION THINKING RECURSIVELY ▸our approach is more declarative ▸ consise algorithm easy to understand ▸ divide - and - conquer! ▸ you will learn how to abstract, next time.