#| (((lambda (x) (lambda (y) (+ x y))) 1) 2) Evaluation with substitution: = ((lambda (y) (+ 1 y)) 2) = (+ 1 2) Evaluation with delayed substitution: = ( ----------------------- | (lambda (y) (+ x y)) | | with x = 1 | 2) ---------------------- = -------------- | (+ x y) | | with x = 1 | | and y = 2 | -------------- To implement the delayed substitution, we need an "environment". Defining "environment" Need three operations: create an empty environment setting a map --- extending lookup a mapping Concrete interface: (empty-env) -- creates an empty envrionment (extend-env env vars vals) --- extends env (apply-env env var) --- returns value for var in env empty-env : -> env extend-env : env list-of-sym list-of-obj -> env apply-env : env sym -> obj Pseudo-formal specification: (empty-env) = { empty-mapping } (extend-env env '(s1 .. sn) '(v1 .. vn)) where the sis are distinct = { function f where f(si) = vi, else f(s) = g(s) where g is the functon for env } (apply-env env s) = { f(s) where f is the function for env } |# ;; -------------------------------------------------- ;; IMPLEMENTATION #1 ;; using define-datatype (define-datatype environment environment? (empty-env-record) (extended-env-record (syms (list-of symbol?)) (vals list?) ; (list-of (lambda (x) #t))) (env environment?))) (define (empty-env) (empty-env-record)) (define (extend-env env vars vals) (extended-env-record vars vals env)) (define (apply-env env sym) (cases environment env [empty-env-record () (error "not there")] [extended-env-record (syms vals old-env) (let ([pos (list-find-position sym syms)]) (cond [pos (list-ref vals pos)] [else (apply-env old-env sym)]))])) (define (list-find-position sym los) (cond [(null? los) #f] [else (cond [(eq? sym (car los)) 0] [else (let ([p (list-find-position sym (cdr los))]) (if p (+ p 1) #f))])])) #| Trying it out: Welcome to DrScheme, version 102. Language: Graphical Full Scheme (MrEd). > (empty-env) (empty-env-record) > (apply-env (empty-env) 'x) reference to undefined identifier: error > (extend-env (empty-env) '(a b c) '(1 2 3)) (extended-env-record (a b c) (1 2 3) (empty-env-record)) > (apply-env (extend-env (empty-env) '(a b c) '(1 2 3)) 'a) 1 > (apply-env (extend-env (empty-env) '(a b c) '(1 2 3)) 'c) 3 > (apply-env (extend-env (extend-env (empty-env) '(a b c) '(1 2 3)) '(c d) '(4 5)) 'c) 4 > (apply-env (extend-env (extend-env (empty-env) '(a b c) '(1 2 3)) '(c d) '(4 5)) 'b) 2 |# ;; -------------------------------------------------- ;; IMPLEMENTATION #2 ;; using functions (define empty-env (lambda () (lambda (sym) (eopl:error 'empty-env "not there")))) (define extend-env (lambda (old-env syms vals) (lambda (sym) (let ([pos (list-find-position sym syms)]) (cond [pos (list-ref vals pos)] [else (old-env sym)]))))) (define (apply-env env sym) (env sym)) #| Example evaluation (error from applying an empty environment): (apply-env (empty-env) 'x) = (apply-env (lambda (sym) (eopl:error ...)) 'x) = ((lambda (sym) (eopl:error ...)) 'x) = (eopl:error ...) => error Example evaluation (find a mapped value): (apply-env (extend-env (empty-env) '(x) '(1)) 'x) = (apply-env (extend-env (lambda (sym) (eopl:error ...)) '(x) '(1)) 'x) = (apply-env (lambda (sym) (let ([pos (list-find-position sym '(x))]) (cond [pos (list-ref '(1) pos)] [else ((lambda (sym) (eopl:error ...)) sym)]))) 'x) = ((lambda (sym) (let ([pos (list-find-position sym '(x))]) (cond [pos (list-ref '(1) pos)] [else ((lambda (sym) (eopl:error ...)) sym)]))) 'x) = (let ([pos (list-find-position 'x '(x))]) (cond [pos (list-ref '(1) pos)] [else ((lambda (sym) (eopl:error ...)) 'x)])) = 1 |# ;; -------------------------------------------------- ;; IMPLEMENTATION #3 ;; the ribcage form, using lists and vectors ;; (see the textbook)