ifeq: resulting expression evaluates to e3 if e1 and e2 evaluate to equal integers (found e4 to be evaluated) [incorrect answer]
compute-free-vars: correctly computes free vars [incorrect answer]
compute-free-vars: no free vars case [incorrect answer]
eval-under-env-c: correctly filters closure environments [incorrect answer]
;; Programming Languages, Homework 5
#lang racket
(provide (all-defined-out)) ;; so we can put tests in a second file
;; definition of structures for MUPL programs - Do NOT change
(struct var (string) #:transparent) ;; a variable, e.g., (var "foo")
(struct int (num) #:transparent) ;; a constant number, e.g., (int 17)
(struct add (e1 e2) #:transparent) ;; add two expressions
(struct ifgreater (e1 e2 e3 e4) #:transparent) ;; if e1 > e2 then e3 else e4
(struct fun (nameopt formal body) #:transparent) ;; a recursive(?) 1-argument function
(struct call (funexp actual) #:transparent) ;; function call
(struct mlet (var e body) #:transparent) ;; a local binding (let var = e in body)
(struct apair (e1 e2) #:transparent) ;; make a new pair
(struct fst (e) #:transparent) ;; get first part of a pair
(struct snd (e) #:transparent) ;; get second part of a pair
(struct aunit () #:transparent) ;; unit value -- good for ending a list
(struct isaunit (e) #:transparent) ;; evaluate to 1 if e is unit else 0
;; a closure is not in "source" programs but /is/ a MUPL value; it is what functions evaluate to
(struct closure (env fun) #:transparent)
;; Problem 1
;; CHANGE (put your solutions here)
(define (racketlist->mupllist lst)
(cond [(null? lst) (aunit)]
[#t (apair (car lst) (racketlist->mupllist (cdr lst)))]))
(define (mupllist->racketlist lst)
(cond [(aunit? lst) null]
[#t (cons (apair-e1 lst) (mupllist->racketlist (apair-e2 lst)))]))
;; Problem 2
;; lookup a variable in an environment
;; Do NOT change this function
(define (envlookup env str)
(cond [(null? env) (error "unbound variable during evaluation" str)]
[(equal? (car (car env)) str) (cdr (car env))]
[#t (envlookup (cdr env) str)]))
;; Do NOT change the two cases given to you.
;; DO add more cases for other kinds of MUPL expressions.
;; We will test eval-under-env by calling it directly even though
;; "in real life" it would be a helper function of eval-exp.
(define (eval-under-env e env)
(cond [(var? e)
(envlookup env (var-string e))]
[(add? e)
(let ([v1 (eval-under-env (add-e1 e) env)]
[v2 (eval-under-env (add-e2 e) env)])
(if (and (int? v1)
(int? v2))
(int (+ (int-num v1)
(int-num v2)))
(error "MUPL addition applied to non-number")))]
;; CHANGE add more cases here
[(int? e) e]
[(ifgreater? e)
(let ([v1 (eval-under-env (ifgreater-e1 e) env)]
[v2 (eval-under-env (ifgreater-e2 e) env)])
(if (and (int? v1)
(int? v2))
(if (> (int-num v1) (int-num v2))
; DO NOT eval v3 and v4 before condition is correct
(eval-under-env (ifgreater-e3 e) env)
(eval-under-env (ifgreater-e4 e) env))
(error "MUPL ifgreater applied to non-number")))]
[(fun? e) (closure env e)]
[(closure? e) e]
[(mlet? e)
(let ([var (mlet-var e)]
[value (eval-under-env (mlet-e e) env)])
(if (string? var)
(let ([extenv (cons (cons var value) env)])
(eval-under-env (mlet-body e) extenv))
(error "MUPL mlet applied to non-string")))]
[(call? e)
(let ([func (eval-under-env (call-funexp e) env)]
[argv (eval-under-env (call-actual e) env)])
(if (closure? func)
(let ([f (closure-fun func)]
[e (closure-env func)])
(let ([fn (fun-nameopt f)]
[ff (fun-formal f)]
[fb (fun-body f)])
(let ([argenv (cons (cons ff argv) e)])
(if (string? fn)
; NOTE: This is (cons fn func), not (cons fn f)
(let ([recargenv (cons (cons fn func) argenv)])
(eval-under-env fb recargenv))
(eval-under-env fb argenv)))))
(error "MUPL call applied to non-closure")))]
[(apair? e)
(let ([v1 (eval-under-env (apair-e1 e) env)]
[v2 (eval-under-env (apair-e2 e) env)])
(apair v1 v2))]
[(fst? e)
(let ([p (eval-under-env (fst-e e) env)])
(if (apair? p)
(let ([v (eval-under-env (apair-e1 p) env)])
v)
(error "MUPL fst applied to non-pair")))]
[(snd? e)
(let ([p (eval-under-env (snd-e e) env)])
(if (apair? p)
(let ([v (eval-under-env (apair-e2 p) env)])
v)
(error "MUPL fst applied to non-pair")))]
[(isaunit? e)
(let ([u (eval-under-env (isaunit-e e) env)])
(if (aunit? u)
(int 1)
(int 0)))]
[(aunit? e) e]
[#t (error (format "bad MUPL expression: ~v" e))]))
;; Do NOT change
(define (eval-exp e)
(eval-under-env e null))
;; Problem 3
(define (ifaunit e1 e2 e3)
(ifgreater (isaunit e1) (int 0)
e2
e3))
(define (mlet* lstlst e2)
(if (null? lstlst)
e2
(let ([e (car lstlst)]
[lst (cdr lstlst)])
(mlet (car e) (cdr e)
(mlet* lst e2)))))
(define (ifeq e1 e2 e3 e4)
(mlet "_x" e1
(mlet "_y" e2
(mlet "_e4" e4
(ifgreater (var "_x") (var "_y")
(var "_e4")
(ifgreater (var "_y") (var "_x")
(var "_e4")
e3))))))
;; Problem 4
(define mupl-map
(fun #f "_mupl-map-f"
(fun "_mupl-map-recursive" "_mupl-map-acc"
(ifaunit (var "_mupl-map-acc")
(aunit)
(mlet "_mupl-map-e" (fst (var "_mupl-map-acc"))
(mlet "_mupl-map-acc-cdr" (snd (var "_mupl-map-acc"))
(mlet "_mupl-map-v" (call (var "_mupl-map-f") (var "_mupl-map-e"))
(apair (var "_mupl-map-v") (call (var "_mupl-map-recursive") (var "_mupl-map-acc-cdr"))))))))))
(define mupl-mapAddN
(mlet "map" mupl-map
(fun #f "_mupl-map-add-n"
(call mupl-map (fun #f "_mupl-map-element"
(add (var "_mupl-map-element") (var "_mupl-map-add-n")))))))
;; Challenge Problem
(struct fun-challenge (nameopt formal body freevars) #:transparent) ;; a recursive(?) 1-argument function
;; We will test this function directly, so it must do
;; as described in the assignment
(define (compute-free-vars e) "CHANGE")
;; Do NOT share code with eval-under-env because that will make
;; auto-grading and peer assessment more difficult, so
;; copy most of your interpreter here and make minor changes
(define (eval-under-env-c e env) "CHANGE")
;; Do NOT change this
(define (eval-exp-c e)
(eval-under-env-c (compute-free-vars e) null))
Sample solutions for wrong problems
(define (ifeq e1 e2 e3 e4)
(mlet "_x" e1
(mlet "_y" e2
(ifgreater (var "_x") (var "_y")
e4
(ifgreater (var "_y") (var "_x")
e4
e3)))))
(define (compute-free-vars e)
(struct res (e fvs)) ; result type of f (could also use a pair)
(define (f e)
(cond [(var? e) (res e (set (var-string e)))]
[(int? e) (res e (set))]
[(add? e) (let ([r1 (f (add-e1 e))]
[r2 (f (add-e2 e))])
(res (add (res-e r1) (res-e r2))
(set-union (res-fvs r1) (res-fvs r2))))]
[(ifgreater? e) (let ([r1 (f (ifgreater-e1 e))]
[r2 (f (ifgreater-e2 e))]
[r3 (f (ifgreater-e3 e))]
[r4 (f (ifgreater-e4 e))])
(res (ifgreater (res-e r1) (res-e r2) (res-e r3) (res-e r4))
(set-union (res-fvs r1) (res-fvs r2) (res-fvs r3) (res-fvs r4))))]
[(fun? e) (let* ([r (f (fun-body e))]
[fvs (set-remove (res-fvs r) (fun-formal e))]
[fvs (if (fun-nameopt e)
(set-remove fvs (fun-nameopt e))
fvs)])
(res (fun-challenge (fun-nameopt e) (fun-formal e)
(res-e r) fvs)
fvs))]
[(call? e) (let ([r1 (f (call-funexp e))]
[r2 (f (call-actual e))])
(res (call (res-e r1) (res-e r2))
(set-union (res-fvs r1) (res-fvs r2))))]
[(mlet? e) (let* ([r1 (f (mlet-e e))]
[r2 (f (mlet-body e))])
(res (mlet (mlet-var e) (res-e r1) (res-e r2))
(set-union (res-fvs r1) (set-remove (res-fvs r2) (mlet-var e)))))]
[(apair? e) (let ([r1 (f (apair-e1 e))]
[r2 (f (apair-e2 e))])
(res (apair (res-e r1) (res-e r2))
(set-union (res-fvs r1) (res-fvs r2))))]
[(fst? e) (let ([r (f (fst-e e))])
(res (fst (res-e r))
(res-fvs r)))]
[(snd? e) (let ([r (f (snd-e e))])
(res (snd (res-e r))
(res-fvs r)))]
[(aunit? e) (res e (set))]
[(isaunit? e) (let ([r (f (isaunit-e e))])
(res (isaunit (res-e r))
(res-fvs r)))]))
(res-e (f e)))
(define (eval-under-env-c e env)
(cond
[(fun-challenge? e)
(closure (set-map (fun-challenge-freevars e)
(lambda (s) (cons s (envlookup env s))))
e)]
; call case uses fun-challenge as appropriate
; all other cases the same
...)
(define (eval-exp-c e)
(eval-under-env-c (compute-free-vars e) null))
