The Mechanical Evaluation of Expressions – Peter J
Total Page:16
File Type:pdf, Size:1020Kb
Thierry Vilmart The mechanical evaluation Emil Karlén of expressions - 1964 by Peter J. Landin ● Peter Landin is a British computer scientist. ● He invented the SECD machine. ● He was one of the first to realize that the lambda calculus could be used to model a programming language. ● Essential to development of both functional programming and denotational semantics. Plan 1. The importance of the SECD machine 2. SECD – an abstract machine 3. Applicative Expressions (AEs) 4. The SECD machine rules and examples 5. Round up The importance of the SECD machine ● SECD stands for « Stack, Environment, Control, Dump » ● SECD machine was the first attempt to make a computer use lambda- calculus in order to compute arithmetical expressions. ● Two years after this article, in 1966, Landin presented ISWIM, an abstract computer programming language. The operational semantics of ISWIM is defined using Landin's SECD machine and it uses call-by- value. ● Although not implemented, ISWIM has been proved very influential in the development of programming languages, especially functional programming languages such as SASL, Miranda, ML, Haskell and their successors. Goal: evaluation of complex expressions Expressions are converted in a form equivalent to Lambda Calculus Concepts of programming languages can be expressed in Lambda Calculus ● Functions: λ abstractions ● Auxiliary definitions: λ abstractions and applications ● Recursion: the fix operator Applicative Expressions - AEs AEs are lambda calculus extended with some features that are easy to represent by computer hardware (lists, strings, decimal numbers, primitive functions). ● There are three kinds of AEs: – Identifier – Lambda expression – Operator / Operand ● Applicative Expression ::= Identifier I lamb(Identifier, Applicative Expression) I comb(Applicative Expression, Applicative Expression) Recursive definition of val E X ● val E X = value of X given the environment E ● E contains the bindings of identifiers to their respective values ● In lambda-calculus, there is no explicit environment E. Introduction to the SECD machine ● A state transition machine that computes val E X ● State: (Stack,Environment,Control,Dump) ● Transition: like small-step evaluation with 7 evaluation rules: (S,E,C,D) ® (S',E',C',D') ● Transitivity will lead you to val E X: ([],E,[X],[]) ®* ([val E X],E,[],[]) ● Avoids the problem of collision of variable names (that can occur during evaluation by variable substitution) ● Implementation does not use recursion The S, E, C and D The states of the SECD machine consist of four components, all exhibiting stack behavior. ● S for Stack Stores partial results (values) awaiting subsequent use. (value: decimal number, primitive function, λ abstraction (almost)) ● E for Environment A mapping from identifiers to values. ● C for Control A stack of AEs yet to be evaluated plus a special symbol @ meaning that an application should be performed. ● D for Dump A stack of complete states corresponding to evaluations in progress but suspended while other AEs are evaluated. Introduction to the Evaluation Rules Control State following (S,E,C,D) 1 [] Restore from Dump = (S',E',C',D') hd S:S© E© C© D© Push onto new Stack: hd of old Stack (hd of old Stack is the result of an application) 2a Ident x:tC Push onto Stack: lookup E x lookup E x:S E tC D 2b λx.ae:tC Push onto Stack: Closure x ae E Closure x ae E:S E tC D 2c @:tC See other table. 2d Comb f a:tC Push onto Control: [argument, function, @] S E a:f:@:tC D Stack Closure = @:C© State following (S,E,C,D) 2c1 Closure x ae E©:v:tS Store S,E,C,D on Dump, and replace [] (x,v):E© [ae] (tS,E,tC,D) S, C, D. 2c2 PrimFun f:v:tS Push onto Stack: result of application f v:tS E tC D Evaluation of an Identifier Stack Environment Control No Rule Where ... Evaluate: x [] [(ºxº,1)] [Ident ºxº] 1 in the environment x ® 1 [1] [(ºxº,1)] [] 2 2a 1 = lookup E ”x” Control State following (S,E,C,D) 1 [] Restore from Dump = (S',E',C',D') hd S:S© E© C© D© Push onto new Stack: hd of old Stack (hd of old Stack is the result of an application) 2a Ident x:tC Push onto Stack: lookup E x lookup E x:S E tC D 2b λx.ae:tC Push onto Stack: Closure x ae E Closure x ae E:S E tC D 2c @:tC See other table. 2d Comb f a:tC Push onto Control: [argument, function, @] S E a:f:@:tC D Stack Closure = @:C© State following (S,E,C,D) 2c1 Closure x ae E©:v:tS Store S,E,C,D on Dump, and replace [] (x,v):E© [ae] (tS,E,tC,D) S, C, D. 2c2 PrimFun f:v:tS Push onto Stack: result of application f v:tS E tC D Two more concepts ● Numerical constants – An Environment may map an identifier to a numerical constant: lookup E x = 1 – A numerical constant is a value ● Primitive functions – A function with predefined computation: acos(1) = 0 – A primitive function is a value Evaluation of Function Application Stack Environment Control No Rule Where ... Evaluate: f x [] E0 [Comb (Ident ªfº) (Ident ºxº)] 1 [] E0 [Ident ºxº,Ident ºfº,@] 2 in the environment E0: 2d x ® 1 [1] E0 [Ident ºfº,@] 3 2a 1 = lookup E0 ”x” f ® acos (a primitive function) [acos,1] E0 [@] 4 2a acos = lookup E0 ”f” [0] E0 [] 5 2c2 0 = acos(1) Control State following (S,E,C,D) 1 [] Restore from Dump = (S',E',C',D') hd S:S© E© C© D© Push onto new Stack: hd of old Stack (hd of old Stack is the result of an application) 2a Ident x:tC Push onto Stack: lookup E x lookup E x:S E tC D 2b λx.ae:tC Push onto Stack: Closure x ae E Closure x ae E:S E tC D 2c @:tC See other table. 2d Comb f a:tC Push onto Control: [argument, function, @] S E a:f:@:tC D Stack Closure = @:C© State following (S,E,C,D) 2c1 Closure x ae E©:v:tS Store S,E,C,D on Dump, and replace [] (x,v):E© [ae] (tS,E,tC,D) S, C, D. 2c2 PrimFun f:v:tS Push onto Stack: result of application f v:tS E tC D One more concept ● Closure – Represents a lambda abstraction (λv.X) in a fixed environment (E): Closure v X E – A closure is a value Control State following (S,E,C,D) 1 [] Restore from Dump = (S',E',C',D') hd S:S© E© C© D© Push onto new Stack: hd of old Stack (hd of old Stack is the result of an application) 2a Ident x:tC Push onto Stack: lookup E x lookup E x:S E tC D 2b λx.ae:tC Push onto Stack: Closure x ae E Closure x ae E:S E tC D 2c @:tC See other table. 2d Comb f a:tC Push onto Control: [argument, function, @] S E a:f:@:tC D Stack Closure = @:C© State following (S,E,C,D) 2c1 Closure x ae E©:v:tS Store S,E,C,D on Dump, and replace [] (x,v):E© [ae] (tS,E,tC,D) S, C, D. 2c2 PrimFun f:v:tS Push onto Stack: result of application f v:tS E tC D Evaluation of Abstraction Application Stack Env. Control Dump No Rule [] E0 [(λy.y) x] [] 1 Evaluate: (λy.y) x [] [x,(λy.y),@] 2 2d in the environment E0: [1] [(λy.y),@] 3 2a x ® 1 [Closure y y E0,1] [@] 4 2b [] (ºyº,1):E0 [y] ([],E0,[],[]) 5 2c1 [1] [] 6 2a [1] E0 [] [] 7 1 Control State following (S,E,C,D) 1 [] Restore from Dump = (S',E',C',D') hd S:S© E© C© D© Push onto new Stack: hd of old Stack (hd of old Stack is the result of an application) 2a Ident x:tC Push onto Stack: lookup E x lookup E x:S E tC D 2b λx.ae:tC Push onto Stack: Closure x ae E Closure x ae E:S E tC D 2c @:tC See other table. 2d Comb f a:tC Push onto Control: [argument, function, @] S E a:f:@:tC D Stack Closure = @:C© State following (S,E,C,D) 2c1 Closure x ae E©:v:tS Store S,E,C,D on Dump, and replace [] (x,v):E© [ae] (tS,E,tC,D) S, C, D. 2c2 PrimFun f:v:tS Push onto Stack: result of application f v:tS E tC D Mechanical evaluation Transitions between configurations: Landin has no types but a general procedure for all identifiers. Using types simplifies greatly the implementation (con and var) transform cfg(S,E,C,D) = ( E(head(C) = val E X ) 1. if head(C) is a constant then cfg([head(C) l S], E, tail(C), D) 2. else if headC) is a variable then cfg(E(head(C)) l S], E, tail(C), D) 3. else if head(C) is an application (Rator Rand) then cfg(S, E, (Rator, Rand @ l tail(C)], D) 4. else if head(C) is a lambda abstraction, Lambda V. B then cfg([closure(V,B,E)| S], E, tail(C), D) 5. else if head(C) = @ and head(tail((S)) is a predefined function f then cfg([f(head(S)) l tail(tail(S))], E, tail(C), D) 6. else if head(C) = @ and head(tail(S)) = closure(V,B,E1) then cfg([ ], {V --> head(S) }E1, [B], cfg(tail(tail(S)),E,tail(C),D)) 7. else if C=[ ] then cfg([head(S)lS1], E1, C1, D1) where D = cfg(S1,E1,C1,D1) Run of SECD in Prolog Example: evaluation of « minus 5 2 » ?- interpret(cfg([ ], nil, [comb(con(minus), con([5,2]))], nil), Result).