TDDC74 Programmering: Abstraktion och modellering VT 2015 Johannes Schmidt Institutionen för datavetenskap Linköpings universitet Lecture 7 State and environment model Part 1 • Muddy-card results • Dugga1-solutions • Functional programming, substitution model • Applicative order versus normal order • set! • Substitution model does not work anymore Part 2 • Introduction to environment diagrams • SICP-Book chapter: 3 © Jalal Maleki, 2012 Muddy-card evaluation Occurred more than once: 13 good labs and lab tasks 3 good labasses 4 good tutorials 4 all fine! 5 good examples on lectures 13 good lectures 4 good that lectures in English 3 good that slides are uploaded before the lectures 5 load up slides before the lectures 2 more examples in the lectures 3 learn how to handle the light 7 lectures too slow 5 lectures at good pace / too fast 3 more examples in tutorials 2 more time for tutorials / too many tasks 2 book in pdf © Jalal Maleki, 2012 Part 1 Functional programming Until now: functional programming (Lectures 1-3 + 4-6) Functional programs = encodings of mathematical functions: (define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) An expression always evaluates to the same value. E.g. > (factorial 4) 24 > (factorial 4) 24 © Jalal Maleki, 2012 Functional programming (define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) Can be understood with the substitution model: (factorial 4) (* 4 (factorial 3)) (* 4 (* 3 (factorial 2))) (* 4 (* 3 (* 2 (factorial 1)))) (* 4 (* 3 (* 2 1))) (* 4 (* 3 2)) (* 4 6) 24 © Jalal Maleki, 2012 A Remark on the substitution model • Describes what happens when we apply a procedure on a number of arguments • Two variants of substitution orders • Applicative order: evaluate the arguments, then go into the procedure’s body with the evaluated arguments • Normal order: go immediately into the procedure’s body with the unevaluated arguments © Jalal Maleki, 2012 Applicative order Normal order (square (* 4 2)) (square 8) (* 8 8) 64 (square (* 4 2)) (* (* 4 2) (* 4 2)) (* 8 8) 64 A Remark on the substitution model • Applicative order: evaluate the arguments, then go into the procedure’s body with the evaluated arguments • Normal order: go immediately into the procedure’s body with the unevaluated arguments (define (square x) (* x x)) (define (sum-of-squares a b) (+ (square a) (square b))) (sum-of-squares (+ 2 1) (* 2 2)) Normal order ? Applicative order ? © Jalal Maleki, 2012 A Remark on the substitution model (define (square x) (* x x)) (define (sum-of-squares a b) (+ (square a) (square b))) (sum-of-squares (+ 2 1) (* 2 2)) Normal order Applicative order (sum-of-squares (+ 2 1) (* 2 2)) (sum-of-squares 3 4) (+ (square 3) (square 4)) (+ (* 3 3) (* 4 4)) (+ 9 16) 25 ; number of operations: 5 (sum-of-squares (+ 2 1) (* 2 2)) (+ (square (+ 2 1)) (square (* 2 2))) (+ (* (+ 2 1) (+ 2 1)) (* (* 2 2) (* 2 2))) (+ (* 3 3) (* 4 4)) (+ 9 16) 25 ; number of operations: 7 © Jalal Maleki, 2012 Functional vs Imperative programming Functional: An expression always evaluates to the same value Imperative: we break with this rule How? With set! • set! is used to change the value bound to a name • Syntax: (set! <variable> <value>) • Example: (set! x 5) (so called assignment) © Jalal Maleki, 2012 Changing global state (define value 0) (define flip (lambda () (set! value (- 1 value)) value))) (flip) -> 1 (flip) -> 0 (flip) -> 1 © Jalal Maleki, 2012 What value does (set! ...) return? Functional programming: Every expression evaluates to a value. So what about set! ? set! returns the value #<void> Usually not displayed. You can display it with an explicit display instruction. You can get the #<void>-value also by calling the function void: > (set! x 5) > (display (set! x 5)) #<void> > (void) > (display (void)) #<void> Procedures that change values (assignments) are said to have side effects. By convention they have the exklamation mark ! at the end of their name. Side effect procedures often return #<void>. © Jalal Maleki, 2012 Simulate a bank account (define balance 100) (define withdraw (lambda (amount) (set! balance (- balance amount)) balance)) >(withdraw 10) 90 >(withdraw 10) 80 >(withdraw 10) 70 © Jalal Maleki, 2012 Simulate two bank accounts? (define balance 100) (define withdraw (lambda (amount) (set! balance (- balance amount)) balance)) (define withdraw2 (lambda (amount) (set! balance (- balance amount)) balance)) >(withdraw 10) 90 >(withdraw2 20) 70 © Jalal Maleki, 2012 Not nice! Better: make balance local Simulate two bank accounts! (define withdraw (let ((balance 100)) (lambda (amount) (set! balance (- balance amount)) balance))) (define withdraw2 (let ((balance 100)) (lambda (amount) (set! balance (- balance amount)) balance))) >(withdraw 10) 90 >(withdraw2 20) 80 © Jalal Maleki, 2012 => Changing local state What is the difference? (define withdrawA (let ((balance 100)) (lambda (amount) (set! balance (- balance amount)) balance))) (define withdrawB (lambda (amount) (let ((balance 100)) (set! balance (- balance amount)) balance))) © Jalal Maleki, 2012 Substitution model fails • Substitution Model fails to work on procedures with side effects, that is, when states are mutated • For example, although the first argument of set! is a name, it has other semantics (meaning) – it can not be substituted by a value. (define (change state) (set! state (not state))) Try to substitute: (change #f) (set! #f (not #f)) !? © Jalal Maleki, 2012 Why does the substitution model fail? • Substitution is based on the notion that symbols are names for values • Using set! changes symbols to places where values can be stored • The value in such a place can change using assignment with set! • A new model of evaluation is needed: the environment model © Jalal Maleki, 2012