#lang racket (define (transform-if-to-cond code) ; locates every occurrence of an if expression in code and ; transforms it into an equivalent cond ; (if c p q) => (cond (c p) (else q )) (define (trans c p q) (list 'cond (list c p) (list 'else q) ) ) (if (and (list? code) (not (null? code)) (eq? 'if (first code))) ; recursively transform the parts of the if before transforming the if (apply trans (map transform-if-to-cond (rest code))) (if (list? code) ; recursively transform expressions (map transform-if-to-cond code) ; leaf expression, leave alone code) )) (define (transform-let-to-apply code) ; locates every occurrence of an let expression in code and ; transforms it into an equivalent lambda applied to the values. ; (let ( (v1 e1) (v2 e2) ... (vn en) ) b1 b2 ... bk ) ; => ; ((lambda (v1 v2 ... vn) b1 b2 ... bk) e1 e2 ... en) ; vars: list of variables being defined (v1 v2 ... vn) ; exprs list of defining expressions (e1 e2 ... en) to evaluate ; body: list of code inside the let (b1 b2 ... bk) (define (trans vars exprs body) (append (list (append (list 'lambda vars) body)) exprs) ) (if (and (list? code) (not (null? code)) (eq? 'let (first code))) (let ( (vars (map first (second code)) ) (exprs (map second (second code)) ) (body (rest (rest code)) ) ) ; recursively transform (trans vars (map transform-let-to-apply exprs) (map transform-let-to-apply body)) ) (if (list? code) ; recursively transform expressions (map transform-let-to-apply code) ; leaf expression, leave alone code) )) (define c1 '(if #t "c1-true" "c1-false" )) (define c2 '(if #f (if (and #t (if #f #t #f)) "c11" "c12" ) "c21" )) (define c3 '(let ( (x 1) (y (+ 2 3)) (z (if #t 42 -1)) ) (println "let-1") (+ x y z) ) ) (define code-1 '(let ( (x 1) (y 2) ) ;(println (list "got" x y)) (let ( (z (+ x y)) ) ;(println (list "z" z)) (if (< x y) (list "x smaller") (list "y smaller") ) ) )) ; why this does not work is explained in http://docs.racket-lang.org/guide/eval.html ; the definitions window does not have a namespace by default. (define ns (make-base-namespace)) (define (test1) (println c1) (println (eval c1 ns)) (println (transform-if-to-cond c1)) (println (eval (transform-if-to-cond c1) ns)) (newline) (println c2) (println (eval c2 ns)) (println (transform-if-to-cond c2)) (println (eval (transform-if-to-cond c2) ns)) ) ;(test1) ; our own println ; displayln will drop the " " around strings, which makes it difficult to ; read the transformed code. So we use println instead. (define (println s) (print s) (newline)) (define (test2a) (println c3) (println (eval c3 ns)) (println (transform-let-to-apply c3)) (println (eval (transform-let-to-apply c3) ns)) (newline) (println code-1) (println (eval code-1 ns)) (println (transform-let-to-apply code-1)) (println (eval (transform-let-to-apply code-1) ns)) ) (define (test-1) (newline) (println code-1) (println (eval code-1)) (newline) ; test the if transform (define t1 (transform-if-to-cond code-1)) (println t1) (println (eval t1)) (newline) ; test the let transform (define t2 (transform-let-to-apply code-1)) (println t2) (println (eval t2)) (newline) ; test the two different composition orders of the transforms (define t3 (transform-let-to-apply (transform-if-to-cond code-1))) (println t3) (println (eval t3)) (newline) (define t4 (transform-if-to-cond(transform-let-to-apply code-1))) (println t4) (println (eval t4)) )