(module mp6 (lib "eopl.ss" "eopl") (require "lang.scm") ; for expression datatype (provide exp-to-mnum transform-diff-zero-simple transform-diff-zero*) ;; A Maybe[X] is one of: ;; - X ;; - #f ;; exp-to-mnum : Exp -> Maybe[Number] ;; usage: (exp-to-mnum e) returns n if e = (const-exp n); otherwise #f (define exp-to-mnum (lambda (e) (cases expression e (const-exp (n) n) (else #f)))) ;; transform-diff-zero-simple : Exp -> Maybe[Exp] ;; usage: (transform-diff-zero-simple e) returns e' if ;; e = (diff-exp e' (const-exp 0)), otherwise returns #f (define transform-diff-zero-simple (lambda (e) (cases expression e ;; The core of the transformation (diff-exp (lft rgt) (cond ((and (exp-to-mnum rgt) (= 0 (exp-to-mnum rgt))) lft) (else #f))) (else #f)))) ;; transform-diff-zero* : Exp -> Exp ;; usage: (transform-diff-zero* exp) returns exp' ;; where exp' is the result of iteratively replacing -(e,0) with e ;; in exp as many times as possible. (define transform-diff-zero* (lambda (e) (cases expression e (const-exp (n) e) ;; no subexpressions, and transform inapplicable. (diff-exp (lft rgt) (let ((lft* (transform-diff-zero* lft)) (rgt* (transform-diff-zero* rgt))) ;; Note we check applicability using rgt* rather than rgt. ;; What would happen if we instead checked applicability ;; using rgt below? (cond ((and (exp-to-mnum rgt*) (= 0 (exp-to-mnum rgt*))) lft*) (else (diff-exp lft* rgt*))))) (zero?-exp (e) (zero?-exp (transform-diff-zero* e))) (if-exp (test then else) (if-exp (transform-diff-zero* test) (transform-diff-zero* then) (transform-diff-zero* else))) (var-exp (id) e) ;; no subexpressions, and transform inapplicable. (let-exp (x binding-exp body) (let-exp x (transform-diff-zero* binding-exp) (transform-diff-zero* body))) (proc-exp (x body) (proc-exp x (transform-diff-zero* body))) (call-exp (rator-exp rand-exp) (call-exp (transform-diff-zero* rator-exp) (transform-diff-zero* rand-exp))) (letrec-exp (fs xs es body) (letrec-exp fs xs (map transform-diff-zero* es) (transform-diff-zero* body))) (begin-exp (exp remaining-exps) (begin-exp (transform-diff-zero* exp) (map transform-diff-zero* remaining-exps))) (newref-exp (exp) (newref-exp (transform-diff-zero* exp))) (deref-exp (exp) (deref-exp (transform-diff-zero* exp))) (setref-exp (lhs-exp rhs-exp) (setref-exp (transform-diff-zero* lhs-exp) (transform-diff-zero* rhs-exp))) ))) )