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
● I use mode in call-exp, var-exp and apply-procedure
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))
))
Semantics of the changed expressions
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 call-exp, the argument of
the function is evaluated with
value-of only if we have call
by value.
In case of call by reference
and call by need, the expression is evaluated with value-of-
operand:
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)))))))
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
data-structures.scm
(define value-of-thunk
(lambda (th)
(cases thunk th
(a-thunk (exp1 saved-env)
(value-of exp1 saved-env)))))
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
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
> (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
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?

Parameter passing

  • 1.
    Assignment #7 CSCE 550 “Parameterpassing convention” Georgiana Tache gxt6286
  • 2.
    Statement of theproblem ● 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
  • 3.
    Convention ● The typeof 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)
  • 4.
    Changes in thelexical 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)
  • 5.
    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.
  • 6.
    Semantics of thechanged expressions ● I keep in the store a global variable mode, which will save the annotation ● I update its value once the procedure is declared ● I use mode in call-exp, var-exp and apply-procedure 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)) ))
  • 7.
    Semantics of thechanged expressions 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 call-exp, the argument of the function is evaluated with value-of only if we have call by value. In case of call by reference and call by need, the expression is evaluated with value-of- operand: 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)))))))
  • 8.
    Semantics of thechanged 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)))))))
  • 9.
    Semantics of thechanged 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.
  • 10.
    Semantics of thechanged 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))))))) 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 data-structures.scm (define value-of-thunk (lambda (th) (cases thunk th (a-thunk (exp1 saved-env) (value-of exp1 saved-env))))) The procedure's argument stays as a thunk until it's needed in the body and will be evaluated as a var-exp.
  • 11.
    Examples of testcases 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)”
  • 12.
    Examples of testcases 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 > (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 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
  • 13.