Assignment #7 CSCE 550
“Parameter passing convention” Georgiana Tache gxt6286
Statement of the problem ●
●
A new language AF (Annot-Formal) which extends Mutable Pairs (chapter 4) AF supports: –
Call-by-value Call-by-reference
–
Call-by-need
–
●
●
The type of calling is established at the point of procedure declaration New test cases are added to support the differences between the types of calling
Convention ●
The type of calling is distinguished using the following annotations in front of the procedure argument: –
value
–
ref
–
lenes - for lazy evaluation
●
There is no implicit annotation
●
All proc declarations are required to specify the convention let p = proc (value x) x in (p 10)
Changes in the lexical spec & grammar â—?
Lexical spec supports 3 annotations: (annot ("lenes") symbol) (annot ("value") symbol) (annot ("ref") symbol)
â—?
The grammar for proc is changed to require the type of parameter passing in the procedure declaration (expression ("proc" "(" annot identifier ")" expression) proc-exp)
Abstract Data Types ●
ExpVal = Num + Bool + Proc + Reference + Mutpair + Thunk
●
Thunk = (Expression, Environment)
●
Thunk is used to store the information for evaluating an expression within an environment. Its evaluation is delayed until the last moment.
Semantics of the changed expressions ●
●
I keep in the store a global variable mode, which will save the annotation I update its value once the procedure is declared interp.scm (define mode "") (define value-of-program (lambda (pgm) (initialize-store!) (set! mode (newref 'unspecified)) (…... ))))))
●
interp.scm (proc-exp (annot var body) (begin (setref! mode annot) (proc-val (procedure var body env)) ))
I use mode in call-exp, var-exp and apply-procedure
Semantics of the changed expressions In call-exp, the argument of the function is evaluated with value-of only if we have call by value.
interp.scm (call-exp (rator rand) (let ((proc (expval->proc (value-of rator env))) (arg (if (equal? (deref mode) 'value) (value-of rand env) (value-of-operand rand env)))) (apply-procedure proc arg)))
In case of call by reference and call by need, the expression is evaluated with value-ofoperand: If the operand is a variable then get its value from the environment. If it's an expression not bound to a variable, evaluate it only if we don't have call by need, and also create a new reference for it.
(define value-of-operand (lambda (exp env) (cases expression exp (var-exp (var) (apply-env env var)) (else (newref (if (equal? (deref mode) 'lenes) (a-thunk exp env) (value-of exp env)))))))
Semantics of the changed expressions ● ●
A change in apply-procedure If call by value – create a new reference, otherwise use the same reference (which is either bound before in value-of-operand or bound at the creation of the variable) (define apply-procedure (lambda (proc1 arg) (cases proc proc1 (procedure (var body saved-env) (let ((r (if (equal? (deref mode) 'value) (newref arg) arg))) (let ((new-env (extend-env var r saved-env))) (value-of body new-env)))))))
Semantics of the changed expressions Call by need implementation
â—?
A lazy reference evaluation
(define value-of-operand (lambda (exp env) (cases expression exp (var-exp (var) (apply-env env var)) (else (newref (if (equal? (deref mode) 'lenes) (a-thunk exp env) (value-of exp env)))))))
(define-datatype thunk thunk? (a-thunk (exp1 expression?) (env environment?))) A thunk has an (unevaluated) expression and an environment attached.
Semantics of the changed expressions Call by need implementation ●
Modification in var-exp:
interp.scm (var-exp (var) (if (not (equal? (deref mode) 'lenes)) (deref (apply-env env var)) ; else, lazy evaluation: (let ((ref1 (apply-env env var))) (let ((w (deref ref1))) (if (expval? w) w (let ((v1 (value-of-thunk w))) (begin (setref! ref1 v1) v1)))))))
data-structures.scm (define value-of-thunk (lambda (th) (cases thunk th (a-thunk (exp1 saved-env) (value-of exp1 saved-env))))) If non-lazy evaluation or lazy evaluation of an expval → get the value of the variable from the environment If lazy evaluation of a thunk → evaluate it using value-of-thunk
The procedure's argument stays as a thunk until it's needed in the body and will be evaluated as a var-exp.
Examples of test cases test1.scm "newpair (let p = proc(value x) set x = 4 in let a = 3 in begin (p a); a end, 3)" test2.scm "newpair (let p = proc(ref x) set x = 4 in let a = 3 in begin (p a); a end, 4)"
test4.scm "newpair (let swap = proc (ref x) proc (value y) let temp = x in begin set x = y; set y = temp end in let a = 33 in let b = 44 in begin ((swap a) b); -(a,b) end , 0)" Each test file has a tuple: “newpair (AF-lang-code, expected value)�
Examples of test cases > (run-all) Runs all previous test cases from tests.scm, where I have modified the syntax of proc > (run-all-files) Runs all additional tests defined in new files, folder tests > (run-everything) Runs both of the above
test6.scm "newpair (let p = proc(value f) proc(value x) -(((f f) -(x,1)), -(0,x)) in let newp = proc(lenes n) 25 in (newp ((p p) 5)) , 25)"
Using value or ref instead of lenes → the program doesn't terminate
In top.scm – 2 new functions: run-file: reading and interpreting one test file run-all-files: comparing the expected output with the actual output, for all test files
Questions?