Thierry Vilmart The mechanical evaluation Emil Karlén of expressions - 1964 by Peter J. Landin

is a British computer scientist.

● He invented the SECD machine.

● He was one of the first to realize that the could be used to model a programming language.

● Essential to development of both 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). cfg([ ],nil,[comb(con(minus),con([5,2]))],nil) cfg([], nil, [con(minus), con([5, 2]), @], nil) cfg([con(minus)], nil, [con([5, 2]), @], nil) cfg([con([5, 2]), con(minus)], nil, [@], nil) cfg([3], nil, [], nil)

Result = 3 . Run of SECD in Prolog

Example: evaluation of « (lambda x. square x) 3 »

?­ interpret(cfg([ ],nil,[comb(lamb(x,comb(con(square),var(x))),

con(3))],nil), Result). cfg([], nil, [lamb(x, comb(con(square), var(x))), con(3), @], nil) cfg([closure(x, comb(con(square), var(x)), nil)], nil, [con(3), @], nil) cfg([con(3), closure(x, comb(con(square), var(x)), nil)], nil, [@], nil) cfg([], env(x, con(3), nil), [comb(con(square), var(x))], cfg([], nil, [], nil)) cfg([], env(x, con(3), nil), [con(square), var(x), @], cfg([], nil, [], nil)) cfg([con(square)], env(x, con(3), nil), [var(x), @], cfg([], nil, [], nil)) cfg([con(3), con(square)], env(x, con(3), nil), [@], cfg([], nil, [], nil)) cfg([9], env(x, con(3), nil), [], cfg([], nil, [], nil)) cfg([9], nil, [], nil)

Result = 9 . Relation to other work

● 1975: Gordon Plotkin published a famous paper that examines the relation between the Lambda Calculus and ISWIM, which has an operational semantics given by the SECD machine.

● The paper includes a proof that the semantics defined by the SECD machine is equivalent to a recursively defined function which implements applicative order evaluation of lambda terms. In that order, the bodies of lambda terms are not evaluated and the arguments of combinations are evaluated before they are substituted.

● 1980: SECD machine in a more detailed form, in Peter Henderson's Lispkit Lisp compiler.

● 1989: researchers at the University of Calgary worked on a hardware implementation of the machine. SCDE machine: the seed of Functionnal Programming

● No direct implemention of ISWIM was attempted.

● But Art Evan's PAL and John Reynold's Gedanken captured most of Landin's concepts including powerful transfer-of-control operations. Both of these were dynamically typed.

● Milner's ML may be considered equivalent to ISWIM without the J operator and with type inference.

● Removing all imperative features, and switching to Lazy evaluation (delayed evaluation), led to SASL, Miranda and Haskell. References

● The mechanical evaluation of expressions – Peter J. Landin – 1964

● Executing an SECD Machine Using Logic Programming – Ken Slomeger – 1995 - ACM copyrigt The University of Iowa - Iowa City, Iowa 52242