SUMMARY Christian Schulte cschulte@kth.se Software and Computer Systems School of Information and Communication Technology KTH – Royal Institute of Technology Stockholm, Sweden ID1218 Lecture 12 2009-12-07 Overview 2 Only functional programming summary C++ summary and example questions, see Lecture 10 ID1218, Christian Schulte L12 2009-12-07 Functional Programming 3 Evaluate functions returning results executed by MiniErlang machine Techniques recursion with last-call-optimization pattern matching list processing higher-order programming accumulators ID1218, Christian Schulte L12 2009-12-07 4 MiniErlang Machine ID1218, Christian Schulte L12 2009-12-07 MiniErlang: Values, Expressions, Instructions 5 MiniErlang values V := int | [] | [ V1 | V2 ] MiniErlang expressions E := int | [] | [ E1 | E2 ] | X | F(E1,…, En) where X stands for a variable MiniErlang instructions CONS, CALL ID1218, Christian Schulte L12 2009-12-07 MiniErlang Machine 6 MiniErlang machine Es ; Vs → Es’ ; Vs’ transforms a pair (separated by ;) of expression stack Es and value stack Vs into a new pair of according to topmost element of Es Initial configuration: expression stack Es’ and value stack Vs’ expression we want to evaluate on expression stack Final configuration: single value as result on value stack ID1218, Christian Schulte L12 2009-12-07 MiniErlang: Expressions 7 Evaluate values V Er ; Vs provided → Er ; V Vs V is a value Evaluate list expression [E1|E2]Er ; Vs → E1E2CONSEr ; Vs Evaluate function call F(E1, …, En)Er ; Vs → E1…EnCALL(F/n)Er ; Vs ID1218, Christian Schulte L12 2009-12-07 MiniErlang: Instructions 8 CONS instruction CONSEr ; V1V2Vs → Er ; [V2|V1]Vs CALL instruction CALL(F/n)Er ; V1…VnVs → s(E)Er ; Vs F(P1, …, Pn) -> E first clause of F/n such that [P1, …, Pn] matches [Vn, …,V1] with substitution s ID1218, Christian Schulte L12 2009-12-07 MiniErlang Pattern Matching 9 Patterns P := int match(P,V) | [] | [ P1 | P2 ] | s:=try(P,V) if errors or XV1, XV2 s withV1≠V2 then no else s where try(i,i) try([],[]) try([P1|P2],[V1|V2]) try(X,V) otherwise = = = try(P1,V1)try(P2,V2) = {XV} = {error} ID1218, Christian Schulte L12 2009-12-07 X Substitution 10 Defined over structure of expressions s(i) s([]) s([E1|E2]) s(F(E1, …, En)) s(X) = i = [] = [s(E1)|s(E2)] = F(s(E1), …, s(En)) = if XV s then V else X ID1218, Christian Schulte L12 2009-12-07 11 Iterative Computations ID1218, Christian Schulte L12 2009-12-07 A Better Length? 12 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? ID1218, Christian Schulte L12 2009-12-07 Running l/1 13 l([1,2,3]) ; → [1,2,3]CALL(l/1) ; → CALL(l/1) ; [1,2,3] → 1+l([2,3]) ; → 1l([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 → 1l([3])ADDADD ; 1 → l([3])ADDADD ; 11 → … requires stack space in the length of list ID1218, Christian Schulte L12 2009-12-07 Running l/2 14 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] → 01ADDCALL(l/2) ; [2,3] → 1ADDCALL(l/2) ; 0[2,3] → ADDCALL(l/2) ; 10[2,3] → CALL(l/2) ; 1[2,3] → l([3],1+1) ; → … requires constant stack space! ID1218, Christian Schulte L12 2009-12-07 Iterative Computations 15 Iterative computations run with constant stack space Make use of last optimization call correspond to loops essentially Tail recursive functions computed by iterative computations ID1218, Christian Schulte L12 2009-12-07 16 Making Computations Iterative Accumulators ID1218, Christian Schulte L12 2009-12-07 Recursive Function 17 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 ID1218, Christian Schulte L12 2009-12-07 Using Accumulators 18 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 ID1218, Christian Schulte L12 2009-12-07 State Invariant for pow/2 19 The invariant is XN = pow(X,N-i) * Xi where i is the current iteration Capture invariant with accumulator for Xi initially (i=0) finally (i=N) 1=X0 XN ID1218, Christian Schulte L12 2009-12-07 The pow/3 Function 20 pow(_,0,A) -> A; pow(X,N,A) -> pow(X,N-1,X*A). pow(X,N) -> pow(X,N,1). ID1218, Christian Schulte L12 2009-12-07 Naïve Reverse Function 21 rev([]) -> []; rev([X|Xr]) -> app(rev(Xr),[X]). Some abbreviations r(Xs) Xs ++ Ys for rev(Xs) for app(Xs,Ys) ID1218, Christian Schulte L12 2009-12-07 Invariant for rev 22 Now it is easy to see that rev([x1, …, xn]) = rev([xi+1, …, xn]) ++ [xi, …, x1] as we go along ID1218, Christian Schulte L12 2009-12-07 rev Final 23 rev([],Ys) -> Ys; rev([X|Xr],Ys) -> rev(Xr,[X|Ys]). Is tail recursive now Cost: n+1 calls for list with n elements ID1218, Christian Schulte L12 2009-12-07 24 Higher-Order Programming ID1218, Christian Schulte L12 2009-12-07 Generic Procedures 25 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 … ID1218, Christian Schulte L12 2009-12-07 Map 26 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 ID1218, Christian Schulte L12 2009-12-07 Using Map 27 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]) ID1218, Christian Schulte L12 2009-12-07 Other Examples 28 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 ID1218, Christian Schulte L12 2009-12-07 Folding Lists 29 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 ID1218, Christian Schulte L12 2009-12-07 Left-Folding 30 Two values define “folding” initial value 0 for sl binary function + for sl Left-folding foldl(F,[x1 , …, xn],S) F(… F(F(S,x1),x2) …,xn) or (…((S F x1) F x2) … F xn) ID1218, Christian Schulte L12 2009-12-07 foldl 31 foldl(_,[],S) -> S; foldl(F,[X|Xr],S) -> foldl(F,Xr,F(S,X)). ID1218, Christian Schulte L12 2009-12-07 Right-Folding 32 Two values define “folding” initial value binary function Right-folding foldr(F,[x1 … xn],S) F(x1,F(x2, … F(xn,S)…)) or x1F(x2 F( … (xn F S) … )) ID1218, Christian Schulte L12 2009-12-07 foldr 33 foldr(_,[],S) -> S; foldr(F,[X|Xr],S) -> F(X,foldr(F,Xr,S)). ID1218, Christian Schulte L12 2009-12-07 34 Concurrency ID1218, Christian Schulte L12 2009-12-07 Erlang Concurrency Primitives 35 Creating processes for function value F spawn(M,F,As) for function F in module M with argument list As spawn(F) Sending messages PID ! message Receiving messages receive … end with clauses Who am I? self() returns the PID of the current process ID1218, Christian Schulte L12 2009-12-07 Processes 36 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) ID1218, Christian Schulte L12 2009-12-07 Message Sending 37 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 ID1218, Christian Schulte L12 2009-12-07 Message Receipt 38 Only receive inspects mailbox Messages are processed in order of arrival all messages are put into the mailbox 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 ID1218, Christian Schulte L12 2009-12-07 39 Communication Patterns ID1218, Christian Schulte L12 2009-12-07 Broadcast 40 foreach(_,[]) -> void; foreach(F,[X|Xr]) -> F(X),foreach(Xr). broadcast(PIDs,M) -> foreach(fun(PID) -> PID ! M end,PIDs). ID1218, Christian Schulte L12 2009-12-07 Broadcast With Ordered Reply 41 collect(PIDs,M) -> map(fun (P) -> P ! {self(),M}, receive {P,Reply} -> Reply end end, PIDs). Collect a reply from all processes in order ID1218, Christian Schulte L12 2009-12-07 Low-latency Collect 42 collect(PIDs,M) -> foreach(fun (P) -> P ! M end, PIDs), map(fun (P) -> receive {P,R} -> R end end, PIDs). No order ID1218, Christian Schulte L12 2009-12-07 43 Coordination ID1218, Christian Schulte L12 2009-12-07 Protocols 44 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 ID1218, Christian Schulte L12 2009-12-07 Choosing a Process 45 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 ID1218, Christian Schulte L12 2009-12-07 Master: Blueprint 46 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 ID1218, Christian Schulte L12 2009-12-07 Slave: Blueprint 47 slave() -> receive {M,propose} -> R=…, M ! {self(),R}, receive {M,accept} -> …; {M,reject} -> … end end ID1218, Christian Schulte L12 2009-12-07 Avoiding Deadlock 48 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? ID1218, Christian Schulte L12 2009-12-07 Avoiding Deadlock 49 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 ID1218, Christian Schulte L12 2009-12-07 Liveness Properties 50 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 ID1218, Christian Schulte L12 2009-12-07 51 Process State Reconsidered ID1218, Christian Schulte L12 2009-12-07 State and Concurrency 52 Difficult to guarantee that state is maintained consistently in a concurrent setting Typically needed: atomic execution of several statements together Processes guarantee atomic execution ID1218, Christian Schulte L12 2009-12-07 Locking Processes 53 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 ID1218, Christian Schulte L12 2009-12-07 A Lockable Process 54 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. ID1218, Christian Schulte L12 2009-12-07 Safety Properties 55 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") ID1218, Christian Schulte L12 2009-12-07 56 Runtime Efficiency ID1218, Christian Schulte L12 2009-12-07 Approach 57 Take MiniErlang program Take execution time for each expression Give equations for runtime of functions Solve equations Determine asymptotic complexity ID1218, Christian Schulte L12 2009-12-07 Execution Times for Expressions 58 Give inductive definition based on function definition and structure of expressions Function definition pattern Simple expression values matching and guards and list construction More involved expression function call recursive function call leads to recursive equation often called: recurrence equation ID1218, Christian Schulte L12 2009-12-07 Execution Time: T(E) 59 Value T(V) = cvalue List construction T([E1|E2]) = ccons + T(E1) + T(E2) Time T(E) needed for executing expression E how MiniErlang machine executes E ID1218, Christian Schulte L12 2009-12-07 Function Call 60 For a function F define a function TF(n) for its runtime and determine size of input for call to F input for a function ID1218, Christian Schulte L12 2009-12-07 Function Call 61 T(F(E1, ..., Ek)) = ccall + T(E1) + ... + T(Ek) + TF(size(IF({1, ..., k}))) input size arguments IF({1, ..., k}) input arguments for F size(IF({1, ..., k})) size of input for F ID1218, Christian Schulte L12 2009-12-07 Function Definition 62 Assume function F defined by clauses H1 -> B1; …; Hk -> Bk. TF(n) = cselect + max { T(B1), …, T(Bk) } ID1218, Christian Schulte L12 2009-12-07 Example: app/2 63 app([],Ys) -> Ys; app([X|Xr],Ys) -> [X|app(Xr,Ys)]. What do we want to compute Tapp(n) Knowledge needed input argument size function first argument length of list ID1218, Christian Schulte L12 2009-12-07 Append: Recurrence Equation 64 Analysis yields Tapp(0) = c1 Tapp(n) = c2 + Tapp(n-1) Solution to recurrence is Tapp(n) = c1 + c2 n Asymptotic complexity Tapp(n) is of O(n) “linear complexity” ID1218, Christian Schulte L12 2009-12-07 Recurrence Equations 65 Analysis in general yields a system T(n) T(0), T(1), … defined in terms of T(m1), …, T(mk) for m1, …, mk < n values for certain n Possibilities solve recurrence equation (difficult in general) lookup asymptotic complexity for common case ID1218, Christian Schulte L12 2009-12-07 Common Recurrence Equations T(n) c + T(n–1) Asymptotic Complexity O(n) c1 + c2n + T(n–1) O(n2) c + T(n/2) O(log n) c1 + c2n + T(n/2) O(n) c + 2T(n/2) O(n) c + 2T(n-1) O(2n) c1 + c2n + T(n/2) O(n log n) L12 2009-12-07 ID1218, Christian Schulte 66 67 That’s It! ID1218, Christian Schulte L12 2009-12-07