450 likes | 657 Views
×ž×‘×•× ×ž×•×¨×—×‘ למדעי המחשב בשפת Scheme. תרגול 13. Metacircular Evaluator. 4.1, pages 362-398 definitions file on web. 2. Overview. 1. Eval, apply 2. Change definition 3. Add let, let* 4. Add special forms and, or 5. Abstraction of frame scanning. 3. Evaluator : a program that
E N D
מבוא מורחב למדעי המחשב בשפת Scheme תרגול 13
Metacircular Evaluator 4.1, pages 362-398 definitions file on web 2
Overview • 1. Eval, apply • 2. Change definition • 3. Add let, let* • 4. Add special forms and, or • 5. Abstraction of frame scanning 3
Evaluator: a program that determines meaning of expressions in a programming language. Metacircular: written in the same language that it evaluates
Read-Eval-Print Loop • (define (driver-loop) • 1. PRINT PROMPT • (prompt-for-input input-prompt) • 2. READ INPUT EXPRESSION • (let ((input (read))) • 3. EVALUATE EXPRESSION • (let ((output (mc-eval input the-global-environment))) • … • 4. PRINT RESULT • (user-print output) • 5. LOOP • (driver-loop)))))) 5
Eval-Apply • Mutual recursion between eval and apply • To evaluate a compound expression means to evaluate the sub-expressions recursively, then apply the operator to the arguments. • To apply a function to arguments means to evaluate the body of the function in a new environment. 6
Eval • Evaluate expression in given environment • (define (mc-eval exp env) • (cond • ((self-evaluating? exp) exp) • … • ((application? exp) • (mc-apply (mc-eval (operator exp) env) • (list-of-values (operands exp) env))) • The name mc-eval is used to differ from the primitive eval 7
Apply • Apply procedure to list of arguments • (define (mc-apply procedure arguments) • … • (eval-sequence (procedure-body procedure) • (extend-environment • (procedure-parameters procedure) • arguments • (procedure-environment procedure)))) • The name mc-apply is used to differ from the primitive apply 8
Change definition from (define x 7) to (x := 7) and from (define (square x) (* x x)) to ((square x) := (* x x)) 9
Change eval case • from: • (define (definition? exp) • (tagged-list? exp 'define)) • (define (tagged-list? exp tag) • (if (pair? exp) • (eq? (car exp) tag) false)) • to: • (define (definition? exp) • (and (pair? exp) • (pair? (cdr exp)) • (eq? (cadr exp) ':=))) 10
(car (car (caar (car (cdar Change selectors • (define (definition-variable exp) • (if (symbol? (cadr exp)) • (cadr exp) • (caadr exp))) • (define (definition-value exp) • (if (symbol? (cadr exp)) • (caddr exp) • (make-lambda (cdadr exp) • (cddr exp)))) 11
Adding let, let* Rearranging as another expression 12
let • (let ((<var1> <exp1>) … (<varn> <expn>)) • <body>) • is equivalent to • ((lambda (<var1> … <varn>) <body>) • <exp1> … <expn>) • add a syntactic transformation • let->combination 13
let - case in eval • ((let? exp) • (mc-eval (let->combination exp) env)) let - predicate (define (let? exp) (tagged-list? exp ‘let)) 14
let - constructors • (define (make-combination • function expressions) • (cons function expressions)) 15
let - selectors • (define (let-bindings exp) (cadr exp)) • (define (let-body exp) (cddr exp)) • (define (let-variables exp) • (map car (let-bindings exp))) • (define (let-expressions exp) • (map cadr (let-bindings exp))) 16
let - evaluation • (define (let->combination exp) • (make-combination • (make-lambda • (let-variables exp) • (let-body exp)) • (let-expressions exp))) 17
let* • The bindings of are performed sequentially. • Each binding is made in an environment in • which all of the preceding bindings are • visible. • (let* ((x 3) • (y (+ x 2)) • (z (+ x y 5))) • (* x z)) • > 39 18
let* • (let* ((<var1> <exp1>)… • (<varn> <expn>)) • <body>) • is equivalent to • (let ((<var1> <exp1>)) • (let* ((<var2> <exp2>)… • (<varn> <expn>)) • <body>)) • add a syntactic transformation • let*->nested-let 19
let* - example • (let* ((<var1> <exp1>) (<var2> <exp2>)) • <body>) • = • (let ((<var1> <exp1>)) • (let* (<var2> <exp2>)) • <body>)) • = • (let ((<var1> <exp1>)) • (let ((<var2> <exp2>)) • (let* () • <body>))) • = • (let ((<var1> <exp1>)) • (let ((<var2> <exp2>)) • (let () • <body>))) 20
let* - case in eval • ((let*? exp) • (mc-eval (let*->nested-let exp) env)) 21
let* - constructors • (define (make-let bindings body) • (cons ‘let (cons bindings body))) • (define (make-let* bindings body) • (cons ‘let* (cons bindings body))) 22
let* - predicates • (define (let*? exp) • (tagged-list exp ‘let*)) • (define (no-bindings? bindings) • (null? bindings)) 23
let* - selectors • (define (let*-bindings exp) (cadr exp)) • (define (let*-body exp) (cddr exp)) • (define (let*-first-binding bindings) • (car bindings)) • (define (let*-rest-bindings bindings) • (cdr bindings)) 24
let* - evaluation • (define (let*->nested-let exp) • (if (no-bindings? (let*-bindings exp)) • (make-let • (let*-bindings exp) • (let*-body exp)) • (make-let • (list (let*-first-binding • (let*-bindings exp)) ; ((v1 e1)) • (make-let* • (let*-rest-bindings (let*-bindings exp)) • (let*-body exp)))) 25
Special forms: and, or Direct evaluation 26
and, or - cases in eval • (define (mc-eval exp env) • (cond ((self-evaluating? exp) exp) • … • ((and? exp) • (eval-and (and-exps exp) env)) • ((or? exp) • (eval-or (or-exps exp) env)) • ((application? exp) • (mc-apply (mc-eval (operator exp) env) • (list-of-values (operands exp) env))) 27
and, or - predicates • (define (and? exp) • (tagged-list? exp ‘and)) • (define (or? exp) • (tagged-list? exp ‘or)) • (define (no-exps? exps) • (null? exps)) • (define (last-exp? exps) • (null? (cdr exps))) 28
and, or - selectors • (define (and-exps exp) • (cdr exp)) • (define (or-exps exp) • (cdr exp)) • (define (first-exp exps) • (car exps)) • (define (rest-exps exps) • (cdr exps)) 29
and - evaluation • from left to right
and - evaluation • (define (eval-and exps env) • (if (no-exps? exps) true • (let ((first • (mc-eval (first-exp exps) env))) • (if (false? first) false • (if (last-exp? exps) first • (eval-and • (rest-exps exps) env))))) 31
or - evaluation • from left to right 32
or - evaluation • (define (eval-or exps env) • (if (no-exps? exps) false • (let ((first • (mc-eval (first-exp exps) env))) • (if (true? first) first • ;(if (last-exp? exps) false • (eval-or • (rest-exps exps) env))))) 33
Abstraction of frame scanning Exercise 4.12 34
Frames • A frame is a set of bindings, represented as a pair of two lists: variables and values • Constructor • (make-frame variables values) • Selectors • (frame-variables frame) • (frame-values frame) • Mutator • (add-binding-to-frame! var val frame)
Environments • An environment consists of its first frame and an enclosing environment • Constructor • (extend-environment vars vals base-env) • Selectors • (first-frame env) • (enclosing-environment env) • Predefined environments • the-global-environment • the-empty-environment
Frame Scanning • Performed by: • lookup-variable-valueinvoked when evaluating names • set-variable-value!invoked when evaluating set! expressions • define-value!invoked when evaluating definitions
lookup-variable-value • (define (lookup-variable-value var env) • (define (env-loop env) • (define (scan vars vals) • (cond ((null? vars) • (env-loop (enclosing-environment env))) • ((eq? var (car vars)) • (car vals)) • (else (scan (cdr vars) (cdr vals))))) • (if (eq? env the-empty-environment) • (error "Unbound variable" var) • (let ((frame (first-frame env))) • (scan (frame-variables frame) • (frame-values frame))))) • (env-loop env))
set-variable-value! • (define (set-variable-value! var val env) • (define (env-loop env) • (define (scan vars vals) • (cond ((null? vars) • (env-loop (enclosing-environment env))) • ((eq? var (car vars)) • (set-car! vals val)) • (else (scan (cdr vars) (cdr vals))))) • (if (eq? env the-empty-environment) • (error "Unbound variable -- SET!" var) • (let ((frame (first-frame env))) • (scan (frame-variables frame) • (frame-values frame))))) • (env-loop env))
define-variable! • (define (define-variable! var val env) • (let ((frame (first-frame env))) • (define (scan vars vals) • (cond ((null? vars) • (add-binding-to-frame! var val frame)) • ((eq? var (car vars)) • (set-car! vals val)) • (else (scan (cdr vars) (cdr vals))))) • (scan (frame-variables frame) • (frame-values frame))))
All procedures are alike! • Scan the frame for the variable’s name • If found, success operation (return value / set value) • If not in frame, failure operation(continue to next frame / add binding) • Error on empty environment (if this can happen) • We can get better abstraction • Capturing common patterns • Hiding frame scanning / mutation
Generic frame scan • (define (scan-first-frame var env succeed fail) • (define (scan vars vals) • (cond ((null? vars) • (fail)) • ((eq? var (car vars)) • (succeed vals)) • (else (scan (cdr vars) (cdr vals))))) • (if (eq? env the-empty-environment) • (error "Unbound variable" var) • (let ((frame (first-frame env))) • (scan (frame-variables frame) • (frame-values frame)))))
lookup-variable-value • (define (lookup-variable-value var env) • (define (succeed vals) • (get-binding-value vals)) • (define (fail) • (scan-first-frame • var (enclosing-environment env) succeed fail)) • (scan-first-frame var env succeed fail)) • (define (get-binding-value vals) • (car vals))
set-variable-value! • (define (set-variable-value! var val env) • (define (succeed vals) • (set-binding-value! vals val)) • (define (fail) • (scan-first-frame • var (enclosing-environment env) succeed fail)) • (scan-first-frame var env succeed fail)) • (define (set-binding-value! vals val) • (set-car! vals val))
define-variable! • (define (define-variable! var val env) • (define (succeed vals) • (set-binding-value! vals val)) • (define (fail) • (add-binding-to-frame! var val (first-frame env)))(scan-first-frame var env succeed fail))