SUMMARY ID1218 Lecture Christian Schulte Software and Computer Systems School of Information and Communication Technology KTH – Royal Institute of Technology Stockholm, Sweden
Overview Only functional programming summary C++ summary and example questions, see Lecture 10 L ID1218, Christian Schulte 2
Functional Programming L ID1218, Christian Schulte 3 Evaluate functions returning results executed by MiniErlang machine Techniques recursion with last-call-optimization pattern matching list processing higher-order programming accumulators
MiniErlang Machine L ID1218, Christian Schulte
MiniErlang: Values, Expressions, Instructions MiniErlang values V := int | [] | [ V 1 | V 2 ] MiniErlang expressions E := int | [] | [ E 1 | E 2 ] | X | F(E 1,…, E n ) where X stands for a variable MiniErlang instructions CONS, CALL L ID1218, Christian Schulte 5
MiniErlang Machine MiniErlang machine Es ; Vs → Es’ ; Vs’ transforms a pair (separated by ;) of expression stack Es and value stack Vs into a new pair of expression stack Es’ and value stack Vs’ according to topmost element of Es Initial configuration: expression we want to evaluate on expression stack Final configuration: single value as result on value stack L ID1218, Christian Schulte 6
MiniErlang: Expressions Evaluate values V Er ; Vs → Er ; V Vs provided V is a value Evaluate list expression [ E 1 | E 2 ] Er ; Vs → E 1 E 2 CONS Er ; Vs Evaluate function call F(E 1, …, E n ) Er ; Vs → E 1 … E n CALL( F/n ) Er ; Vs L ID1218, Christian Schulte 7
MiniErlang: Instructions CONS instruction CONS Er ; V 1 V 2 Vs → Er ; [ V 2 | V 1 ] Vs CALL instruction CALL( F/n ) Er ; V 1 … V n Vs → s(E ) Er ; Vs F(P 1, …, P n ) -> E first clause of F/n such that [ P 1, …, P n ] matches [ V n, …, V 1 ] with substitution s L ID1218, Christian Schulte 8
MiniErlang Pattern Matching Patterns P :=int | [] | [ P 1 | P 2 ] | X match(P,V) s:=try(P,V) if error s or X V 1, X V 2 s withV 1 ≠V 2 then no else s where try( i, i ) = try( [], [] ) = try( [ P 1 | P 2 ], [ V 1 | V 2 ] )= try(P 1,V 1 ) try(P 2,V 2 ) try(X,V) = {X V} otherwise= {error} L ID1218, Christian Schulte 9
Substitution Defined over structure of expressions s( i ) = i s( [] ) = [] s( [ E 1 | E 2 ] ) = [ s(E 1 ) | s(E 2 ) ] s(F(E 1, …, E n )) = F(s(E 1 ), …, s(E n )) s(X)= if X V s then V else X L ID1218, Christian Schulte 10
Iterative Computations L ID1218, Christian Schulte 11
A Better Length? L ID1218, Christian Schulte l([]) -> 0; l([_|Xr]) -> 1+l(Xr). l([],N) -> N; l([_|Xr],N) -> l(Xr,N+1). Two different functions: l/1 and l/2 Which one is better? 12
Running l/1 l([1,2,3]) ; → [1,2,3] CALL(l/1) ; → CALL(l/1) ; [1,2,3] → 1+l([2,3]) ; → 1 l([2,3]) ADD ; → l([2,3]) ADD ; 1 → [2,3] CALL(l/1) ADD ; 1 → CALL(l/1) ADD ; [2,3] 1 → 1+l([3]) ADD ; 1 → 1 l([3]) ADD ADD ; 1 → l([3]) ADD ADD ; 1 1 → … requires stack space in the length of list L ID1218, Christian Schulte 13
Running l/2 l([1,2,3],0) ; → [1,2,3] 0 CALL(l/2) ; → 0 CALL(l/2) ; [1,2,3] → CALL(l/2) ; 0 [1,2,3] → l([2,3],0+1) ; → [2,3] 0+1 CALL(l/2) ; → 0+1 CALL(l/2) ; [2,3] → 0 1 ADD CALL(l/2) ; [2,3] → 1 ADD CALL(l/2) ; 0 [2,3] → ADD CALL(l/2) ; 1 0 [2,3] → CALL(l/2) ; 1 [2,3] → l([3],1+1) ; → … requires constant stack space! L ID1218, Christian Schulte 14
L ID1218, Christian Schulte Iterative Computations Iterative computations run with constant stack space Make use of last optimization call correspond to loops essentially Tail recursive functions computed by iterative computations 15
Accumulators Making Computations Iterative L ID1218, Christian Schulte
L ID1218, Christian Schulte Recursive Function pow(_,0) -> 1; pow(X,N) -> X*pow(X,N-1). Is not tail-recursive not an iterative function uses stack space in order of N 17
L ID1218, Christian Schulte Using Accumulators Accumulator stores intermediate result Finding an accumulator amounts to finding an invariant recursion maintains invariant invariant must hold initially result must be obtainable from invariant 18
L ID1218, Christian Schulte State Invariant for pow/2 The invariant is X N = pow(X,N- i ) * X i where i is the current iteration Capture invariant with accumulator for X i initially (i=0)1= X 0 finally (i= N ) X N 19
L ID1218, Christian Schulte The pow/3 Function pow(_,0,A) -> A; pow(X,N,A) -> pow(X,N-1,X*A). pow(X,N) -> pow(X,N,1). 20
L ID1218, Christian Schulte Naïve Reverse Function rev([]) -> []; rev([X|Xr]) -> app(rev(Xr),[X]). Some abbreviations r(Xs) for rev(Xs) Xs ++ Ys for app(Xs,Ys) 21
L ID1218, Christian Schulte Invariant for rev Now it is easy to see that rev([ x 1, …, x n ]) = rev([ x i+1, …, x n ]) ++ [ x i, …, x 1 ] as we go along 22
L ID1218, Christian Schulte rev Final rev([],Ys) -> Ys; rev([X|Xr],Ys) -> rev(Xr,[X|Ys]). Is tail recursive now Cost: n+1 calls for list with n elements 23
Higher-Order Programming L ID1218, Christian Schulte
L ID1218, Christian Schulte Generic Procedures Sorting a list in increasing or decreasing order by number or phone book order (maybe even a Swedish phone book!) sorting algorithm + order Mapping a list of numbers to list of square numbers to list of inverted numbers to list of square roots … 25
L ID1218, Christian Schulte Map map(_,[]) -> []; map(F,[X|Xr]) -> [F(X)|map(F,Xr)]. msq(Xs) -> map(fun (X) -> X*X end, Xs). Use map/2 for any mapping function! Syntax of fun like case 26
L ID1218, Christian Schulte Using Map Mapping to square numbers map(fun (X) -> X*X end,[1,2,3]) Mapping to negative numbers map(fun (X) -> -X end,[1,2,3]) 27
L ID1218, Christian Schulte Other Examples filter(F,Xs) returns all elements of Xs for which F returns true any(F,Xs) tests whether Xs has an element for which F returns true all(F,Xs) tests whether F returns true for all elements of Xs 28
L ID1218, Christian Schulte Folding Lists Consider computing the sum of list elements …or the product …or all elements appended to a list …or the maximum … What do they have in common? Consider example: sl 29
L ID1218, Christian Schulte Left-Folding Two values define “folding” initial value 0 for sl binary function + for sl Left-folding foldl(F,[ x 1, …, x n ],S) F(… F(F(S, x 1 ), x 2 ) …, x n ) or (…((S F x 1 ) F x 2 ) … F x n ) 30
L ID1218, Christian Schulte foldl foldl(_,[],S) -> S; foldl(F,[X|Xr],S) -> foldl(F,Xr,F(S,X)). 31
L ID1218, Christian Schulte 32 Right-Folding Two values define “folding” initial value binary function Right-folding foldr(F,[ x 1 … x n ],S) F( x 1,F( x 2, … F( x n,S)…)) or x 1 F ( x 2 F ( … ( x n F S) … ))
L ID1218, Christian Schulte 33 foldr foldr(_,[],S) -> S; foldr(F,[X|Xr],S) -> F(X,foldr(F,Xr,S)).
Concurrency L ID1218, Christian Schulte
Erlang Concurrency Primitives Creating processes spawn(F) for function value F spawn(M,F,As) for function F in module M with argument list As Sending messages PID ! message Receiving messages receive … end with clauses Who am I? self() returns the PID of the current process L ID1218, Christian Schulte 35
Processes Each process has a mailbox incoming messages are stored in order of arrival sending puts message in mailbox Processes are executed fairly if a process can receive a message or compute… …eventually, it will It will pretty soon… simple priorities available (low) L ID1218, Christian Schulte 36
Message Sending Message sending P ! M is asynchronous the sender does not wait until message has been processed continues execution immediately evaluates to M When a process sends messages M1 and M2 to same PID, they arrive in order in mailbox FIFO ordering When a process sends messages M1 and M2 to different processes, order of arrival is undefined L ID1218, Christian Schulte 37
Message Receipt Only receive inspects mailbox all messages are put into the mailbox Messages are processed in order of arrival that is, receive processes mailbox in order If the receive statement has a matching clause for the first message remove message and execute clause always choose the first matching clause Otherwise, continue with next message Unmatched messages are kept in original order L ID1218, Christian Schulte 38
Communication Patterns L ID1218, Christian Schulte
Broadcast foreach(_,[]) -> void; foreach(F,[X|Xr]) -> F(X),foreach(Xr). broadcast(PIDs,M) -> foreach(fun(PID) -> PID ! M end,PIDs). L ID1218, Christian Schulte 40
Broadcast With Ordered Reply collect(PIDs,M) -> map(fun (P) -> P ! {self(),M}, receive {P,Reply} -> Reply end end, PIDs). Collect a reply from all processes in order L ID1218, Christian Schulte 41
Low-latency Collect collect(PIDs,M) -> foreach(fun (P) -> P ! M end, PIDs), map(fun (P) -> receive {P,R} -> R end end, PIDs). No order L ID1218, Christian Schulte 42
Coordination L ID1218, Christian Schulte
L ID1218, Christian Schulte 44 Protocols Protocol: rules for sending and receiving messages programming with processes Examples broadcasting messages to group of processes choosing a process Important properties of protocols safety liveness
L ID1218, Christian Schulte 45 Choosing a Process Example: choosing the best lift, connection, … More general: seeking agreement coordinate execution General idea: Master send message to all slaves containing reply PID select one slave: accept all other slaves: reject Slaves answer by replying to master PID wait for decision from master
Master: Blueprint decide(SPs) -> Rs=collect(SPs,propose), {SP,SPr}=choose(SPs,Rs), SP ! {self(),accept}, broadcast(SPr,reject}. Generic: collecting and broadcasting Specific: choose single process from processes based on replies Rs L ID1218, Christian Schulte 46
Slave: Blueprint slave() -> receive {M,propose} -> R=…, M ! {self(),R}, receive {M,accept} -> …; {M,reject} -> … end L ID1218, Christian Schulte 47
L ID1218, Christian Schulte 48 Avoiding Deadlock Master can only proceed, after all slaves answered will not process any more messages until then receiving messages in collect Slave can only proceed, after master answered will not process any more messages until then What happens if multiple masters for same slaves?
L ID1218, Christian Schulte 49 Avoiding Deadlock Force all masters to send in order: First A, then B, then C, … Guarantee: If A available, all others will be available difficult: what if dynamic addition and removal of lists does not work with low-latency collect low-latency: messages can arrive in any order high-latency: receipt imposes strict order Use an adaptor access to slaves through one single master slaves send message to single master problem: potential bottleneck
Liveness Properties Important property of concurrent programs liveness An event/activity might fail to be live other activities consume all CPU power message box is flooded (denial of services) activities have deadlocked … Difficult: all possible interactions with other processes must guarantee liveness reasoning of all possible interactions L ID1218, Christian Schulte 50
Process State Reconsidered L ID1218, Christian Schulte
L ID1218, Christian Schulte 52 State and Concurrency Difficult to guarantee that state is maintained consistently in a concurrent setting Typically needed: atomic execution of several statements together Processes guarantee atomic execution
Locking Processes Idea that is used most often in languages which rely on state Before state can be manipulated: lock must be acquired for example, one lock per object If process has acquired lock: can perform operations If process is done, lock is released L ID1218, Christian Schulte 53
A Lockable Process outside(F,InS) -> receive {acquire,PID} -> PID ! {ok,self()}, inside(F,InS,PID) end. inside(F,InS,PID) -> receive {release,PID} -> outside(F,InS) {PID,Msg} -> inside(F,F(Msg,InS)); end. L ID1218, Christian Schulte 54
Safety Properties Maintain state of processes in consistent fashion do not violate invariants to not compute incorrect results Guarantee safety by atomic execution exclusion of other processes ("mutual exclusion") L ID1218, Christian Schulte 55
Runtime Efficiency L ID1218, Christian Schulte
L ID1218, Christian Schulte 57 Approach Take MiniErlang program Take execution time for each expression Give equations for runtime of functions Solve equations Determine asymptotic complexity
L ID1218, Christian Schulte 58 Execution Times for Expressions Give inductive definition based on function definition and structure of expressions Function definition pattern matching and guards Simple expression values and list construction More involved expression function call recursive function call leads to recursive equation often called: recurrence equation
L ID1218, Christian Schulte 59 Execution Time: T(E) Value T(V) = c value List construction T( [ E 1 | E 2 ] ) = c cons + T(E 1 ) + T(E 2 ) Time T(E) needed for executing expression E how MiniErlang machine executes E
L ID1218, Christian Schulte 60 Function Call For a function F define a function T F (n)for its runtime and determine size of input for call to F input for a function
L ID1218, Christian Schulte 61 Function Call T(F ( E 1,..., E k ) ) = c call + T(E 1 ) T(E k ) + T F (size(I F ({1,..., k}))) input argumentsI F ({1,..., k}) input arguments for F sizesize(I F ({1,..., k})) size of input for F
Function Definition Assume function F defined by clauses H 1 -> B 1 ; … ; H k -> B k. T F (n) = c select + max { T(B 1 ), …, T(B k ) } L ID1218, Christian Schulte 62
L ID1218, Christian Schulte 63 Example: app/2 app([],Ys) -> Ys; app([X|Xr],Ys) -> [X|app(Xr,Ys)]. What do we want to compute T app (n) Knowledge needed input argumentfirst argument size functionlength of list
L ID1218, Christian Schulte 64 Append: Recurrence Equation Analysis yields T app (0)= c 1 T app (n)= c 2 + T app (n-1) Solution to recurrence is T app (n) = c 1 + c 2 n Asymptotic complexity T app (n) is of O(n)“linear complexity”
L ID1218, Christian Schulte 65 Recurrence Equations Analysis in general yields a system T(n)defined in terms of T(m 1 ), …, T(m k ) for m 1, …, m k < n T(0), T(1), …values for certain n Possibilities solve recurrence equation (difficult in general) lookup asymptotic complexity for common case
L ID1218, Christian Schulte66 Common Recurrence Equations T(n)Asymptotic Complexity c + T(n–1)O(n) c 1 + c 2 n + T(n–1) O(n 2 ) c + T(n/2)O(log n) c 1 + c 2 n + T(n/2) O(n) c + 2T(n/2)O(n) c + 2T(n-1)O(2 n ) c 1 + c 2 n + T(n/2) O(n log n)
That’s It! L ID1218, Christian Schulte