3
;; Author: Matthew Might
4
;; Site: http://matt.might.net/
5
;; http://blog.might.net/
9
;; A compiler from a small, functional
10
;; language into the pure lambda calculus.
12
(require test-engine/racket-tests)
20
;; | (if <exp> <exp> <exp>)
21
;; | (and <exp> <exp>)
32
;; | (let ((<var> <exp>) ...) <exp>)
33
;; | (letrec ((<var> <lam>)) <exp>)
35
;; | (cons <exp> <exp>)
42
;; | (<exp> <exp> ...)
44
;; <lam> ::= (λ (<var> ...) <exp>)
48
(define VOID `(λ (void) void))
52
((λ (f) (f f)) (λ (f) (f f)))))
55
(define TRUE `(λ (t) (λ (f) (t ,VOID))))
56
(define FALSE `(λ (t) (λ (f) (f ,VOID))))
59
(define (church-numeral n)
61
(define (apply-n f n z)
64
[else `(,f ,(apply-n f (- n 1) z))]))
67
[(= n 0) `(λ (f) (λ (z) z))]
69
,(apply-n 'f n 'z)))]))
72
((n (λ (_) ,FALSE)) ,TRUE)))
78
((m f) ((n f) z)))))))
100
(define CONS `(λ (car)
104
((on-cons car) cdr))))))
106
(define NIL `(λ (on-cons)
110
(define CAR `(λ (list)
116
(define CDR `(λ (list)
122
(define PAIR? `(λ (list)
123
((list (λ (_) (λ (_) ,TRUE)))
126
(define NULL? `(λ (list)
127
((list (λ (_) (λ (_) ,FALSE)))
132
(define Y '((λ (y) (λ (F) (F (λ (x) (((y y) F) x)))))
133
(λ (y) (λ (F) (F (λ (x) (((y y) F) x)))))))
137
(define (compile exp)
140
; Symbols stay the same:
143
; Boolean and conditionals:
148
(compile `(,cond (λ () ,t) (λ () ,f)))]
152
(compile `(if ,a ,b #f))]
156
(compile `(if ,a #t ,b))]
159
[(? integer?) (church-numeral exp)]
160
[`(zero? ,exp) `(,ZERO? ,(compile exp))]
161
[`(- ,x ,y) `((,SUB ,(compile x)) ,(compile y))]
162
[`(+ ,x ,y) `((,SUM ,(compile x)) ,(compile y))]
163
[`(* ,x ,y) `((,MUL ,(compile x)) ,(compile y))]
164
[`(= ,x ,y) (compile `(and (zero? (- ,x ,y))
169
[`(cons ,car ,cdr) `((,CONS ,(compile car))
171
[`(car ,list) `(,CAR ,(compile list))]
172
[`(cdr ,list) `(,CDR ,(compile list))]
173
[`(pair? ,list) `(,PAIR? ,(compile list))]
174
[`(null? ,list) `(,NULL? ,(compile list))]
179
`(λ (_) ,(compile exp))]
183
`(λ (,v) ,(compile exp))]
185
[`(λ (,v ,vs ...) ,exp)
188
,(compile `(λ (,@vs) ,exp)))]
191
[`(let ((,v ,exp) ...) ,body)
193
(compile `((λ (,@v) ,body) ,@exp))]
195
[`(letrec [(,f ,lam)] ,body)
197
(compile `(let ((,f (,Y (λ (,f) ,lam))))
200
; Application -- must be last:
203
(compile `(,(compile f) ,VOID))]
207
`(,(compile f) ,(compile exp))]
209
[`(,f ,exp ,rest ...)
211
(compile `((,f ,exp) ,@rest))]
215
(display (format "unknown exp: ~s~n" exp))
216
(error "unknown expression")]))
220
(define (succ n) (+ n 1))
222
(define (natify church-numeral)
223
((church-numeral succ) 0))
225
(define (boolify church-boolean)
226
((church-boolean (λ (_) #t)) (λ (_) #f)))
228
(define (listify f church-list)
230
(λ (car) (λ (cdr) (cons (f car) (listify f cdr)))))
235
(define ns (make-base-namespace))
238
(eval (compile prog) ns))
240
(check-expect (natify (eval `(,PRED ,(compile 0)) ns))
243
(check-expect (natify (eval `(,PRED ,(compile 9)) ns))
246
(check-expect (natify (eval `((,SUM ,(compile 5))
250
(check-expect (natify (ec `(* 3 10)))
253
(check-expect (natify (ec `(- 3 1)))
256
(check-expect (natify (ec `(let ((v 3) (x 10)) v)))
259
(check-expect (boolify (ec `(= 3 3)))
262
(check-expect (listify natify (ec `(cons 4 (cons 3 '()))))
265
(check-expect (natify (ec `(car (cons 3 4))))
268
(check-expect (boolify (ec `(null? (cons 3 4))))
271
(check-expect (boolify (ec `(pair? (cons 3 4))))
274
(define R1 (compile `(letrec [(f (λ (n)
277
(* n (f (- n 1))))))]
280
(check-expect (natify (eval R1 ns))