Due: Wednesday, October 5th, 2016 11:59pm
Implement an interpreter with lazy evaluation and the following grammar:
<Expr> = <Num>
| <Sym>
| {+ <Expr> <Expr>}
| {* <Expr> <Expr>}
| {lambda {<id>} <Expr>}
| {<Expr> <Expr>}
| {let {[<id> <Expr>]} <Expr>}
| {if0 <Expr> <Expr> <Expr>}
| {cons <Expr> <Expr>}
| {first <Expr>}
| {rest <Expr>}That is, a language with single-argument functions and application, an if-zero conditional, and cons, first, and rest operations. (The language does not include recursive bindings or records.) The cons operation does not require its second argument to be a list, so rest can also return a non-list.
Implement your interpreter with the plai-typed language, not a lazy language.
Evaluation of the interpreted langauge must be lazy, however. In particular, if a function never uses the value of an argument, then the argument expression should not be evaluated. Similarly, if the first or rest of a cons cell is never needed, then the first or rest expression should not be evaluated.
Start with more-lazy.rkt. Expand the parse function to support the new forms: if0, cons, first, and rest. Also, as in HW 5, provide an interp-expr function; the interp-expr wrapper for interp should take an expression and return either a number S-expression, `function for a function result, or `cons for a cons result. (Meanwhile, the interp function should never return the symbol `cons, just like the starting interp function never returns the symbol `function.)
(test (interp-expr (parse '10))
'10)
(test (interp-expr (parse '{+ 10 17}))
'27)
(test (interp-expr (parse '{* 10 7}))
'70)
(test (interp-expr (parse '{{lambda {x} {+ x 12}}
{+ 1 17}}))
'30)
(test (interp-expr (parse '{let {[x 0]}
{let {[f {lambda {y} {+ x y}}]}
{+ {f 1}
{let {[x 3]}
{f 2}}}}}))
'3)
(test (interp-expr (parse '{if0 0 1 2}))
'1)
(test (interp-expr (parse '{if0 1 1 2}))
'2)
(test (interp-expr (parse '{cons 1 2}))
`cons)
(test (interp-expr (parse '{first {cons 1 2}}))
'1)
(test (interp-expr (parse '{rest {cons 1 2}}))
'2)
;; Lazy evaluation:
(test (interp-expr (parse '{{lambda {x} 0}
{+ 1 {lambda {y} y}}}))
'0)
(test (interp-expr (parse '{let {[x {+ 1 {lambda {y} y}}]}
0}))
'0)
(test (interp-expr (parse '{first {cons 3
{+ 1 {lambda {y} y}}}}))
'3)
(test (interp-expr (parse '{rest {cons {+ 1 {lambda {y} y}}
4}}))
'4)
(test (interp-expr (parse '{first {cons 5
;; Infinite loop:
{{lambda {x} {x x}}
{lambda {x} {x x}}}}}))
'5)
(test (interp-expr
(parse
'{let {[mkrec
;; This is call-by-name mkrec
;; (simpler than call-by-value):
{lambda {body-proc}
{let {[fX {lambda {fX}
{body-proc {fX fX}}}]}
{fX fX}}}]}
{let {[fib
{mkrec
{lambda {fib}
;; Fib:
{lambda {n}
{if0 n
1
{if0 {+ n -1}
1
{+ {fib {+ n -1}}
{fib {+ n -2}}}}}}}}]}
;; Call fib on 4:
{fib 4}}}))
'5)
(test (interp-expr
(parse
'{let {[mkrec
;; This is call-by-name mkrec
;; (simpler than call-by-value):
{lambda {body-proc}
{let {[fX {lambda {fX}
{body-proc {fX fX}}}]}
{fX fX}}}]}
{let {[nats-from
{mkrec
{lambda {nats-from}
;; nats-from:
{lambda {n}
{cons n {nats-from {+ n 1}}}}}}]}
{let {[list-ref
{mkrec
{lambda {list-ref}
;; list-ref:
{lambda {n}
{lambda {l}
{if0 n
{first l}
{{list-ref {+ n -1}} {rest l}}}}}}}]}
;; Call list-ref on infinite list:
{{list-ref 4} {nats-from 2}}}}}))
'6)| Last update: Tuesday, November 15th, 2016mflatt@cs.utah.edu |