Due: Thursday, October 27th, 2011 10:45am
Start with fae-k.rkt and add two new arithmetic operators: neg and avg. The neg form takes a single number and returns its negation; the avg form takes three numbers and returns the average of the numbers.
<FAE> = .... | {neg <FAE>} | {avg <FAE> <FAE> <FAE>}
As in recent previous homeworks, provide interp-expr, which takes an expression, interprets it with an empty substitution and empty continuation, and produces either a number or 'function.
(test (interp-expr (parse '{neg 2})) -2) (test (interp-expr (parse '{avg 0 6 6})) 4)
Add withcc back to the interpreter:
<FAE> = .... | {withcc <id> <FAE>}
Make interp-expr return 'function when the result is a continuation.
(test (interp-expr (parse '{withcc k 7})) 7) (test (interp-expr (parse '{withcc k k})) 'function) (test (interp-expr (parse '{withcc k {neg {k 3}}})) 3)
Change your interpreter to support multiple or zero arguments to a function, and multiple or zero arguments in a function call:
<FAE> = .... | {fun {<id>*} <FAE>} | {<FAE> <FAE>*}
Assume that each argument <id> is distinct for a fun expression. All continuations still accept a single argument (so supplying multiple arguments to a continuation triggers an error).
(test (interp-expr (parse '{{fun {x y} {- y x}} 10 12})) 2) (test (interp-expr (parse '{fun {} 12})) 'function) (test (interp-expr (parse '{fun {x} {fun {} x}})) 'function) (test (interp-expr (parse '{{{fun {x} {fun {} x}} 13}})) 13) (test (interp-expr (parse '{withcc esc {{fun {x y} x} 1 {esc 3}}})) 3) (test (interp-expr (parse '{{withcc esc {{fun {x y} {fun {z} {+ z y}}} 1 {withcc k {esc k}}}} 10})) 20)
This exercise is optional, for extra credit.
Extend your interpreter to support catching and throwing exceptions:
<FAE> = ... | {try <FAE> catch <FAE>} | {throw}
The try ... catch form evaluates its first <FAE> and returns its value—
unless evaluating the first <FAE> throws an exception by evaluating{throw}, in which case the result of the try expression is the result of the second <FAE>. Of course, catching the exception (and starting to evaluate the second <FAE>) means that the throw is not seen by any enclosing try. The result is undefined if throw is used without a dynamically enclosing catch.
(test (interp-expr (parse '{try 7 catch 8})) 7) (test (interp-expr (parse '{try {throw} catch 8})) 8) (test (interp-expr (parse '{try {+ 1 {throw}} catch 8})) 8) (test (interp-expr (parse '{{fun {f} {try {f} catch 8}} {fun {} {throw}}})) 8) (test (interp-expr (parse '{try {try {throw} catch 8} catch 9})) 8) (test (interp-expr (parse '{try {try {throw} catch {throw}} catch 9})) 9) (test (interp-expr (parse '{try {try 7 catch {throw}} catch 9})) 7) (test (interp-expr (parse '{{withcc esc {try {{withcc k {esc k}}} catch {fun {x} 8}}} {fun {} {throw}}})) 8) (test (interp-expr (parse '{{withcc esc {try {{withcc k {try {esc k} catch {fun {} {fun {y} 9}}}}} catch {fun {x} 8}}} {fun {} {throw}}})) 8)
Hint: The currently active try ... catch is much like a dynamic binding.
Last update: Wednesday, October 19th, 2011mflatt@cs.utah.edu |