-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsection-4.1.2.rkt
138 lines (106 loc) · 3.94 KB
/
section-4.1.2.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#lang sicp
;; TODO ex 4.2
;; TODO ex 4.3
;; ex 4.4
(define (and? exp) (tagged-list? exp 'and))
(define (and-conditions exp) (cdr exp))
(define (eval-and exps env)
(define (loop exps)
(cond ((null? exps) true)
((last-exp? exps) (eval (first-exp exps) env))
((not (true? (eval (first-exp exps) env))) false)
(else (loop (rest-exps exps)))))
(loop (and-conditions exps)))
(define (or? exp) (tagged-list? exp 'or))
(define (or-conditions exp) (cdr exp))
(define (eval-or exps env)
(define (loop exps)
(cond [(null? exps) false]
[(last-exp? exps) (eval (first-exp exps) env)]
[(true? (eval (first-exp exps) env)) true]
[else (loop (rest-exps exps))]))
(loop (or-conditions exps)))
(define (and->if exps)
(let expand ([clauses (and-conditions exps)])
(cond [(null? clauses) 'true]
[(last-exp? clauses) (first-exp clauses)]
[else (make-if (first-exp clauses)
(expand (rest-exps clauses))
'false)])))
(define (or->if exp)
(let expand ((clauses (or-conditions exp)))
(cond ((null? clauses) 'false)
(else (make-if (first-exp clauses)
(first-exp clauses)
(expand (rest-exps clauses)))))))
;; ex 4.5
(define (expand-clauses clauses)
(if (null? clauses)
'false ; no else clause
(let ((first (car clauses))
(rest (cdr clauses)))
(if (cond-else-clause? first)
(if (null? rest)
(sequence->exp (cond-actions first))
(error "ELSE clause isn't last: COND->IF"
clauses))
(if (eq? (car (cond-actions first)) '=>)
(make-if (cond-predicate first)
(list (cadr (cond-actions first))
(cond-predicate first))
(expand-clauses rest))
(make-if (cond-predicate first)
(sequence->exp (cond-actions first))
(expand-clauses rest)))))))
; ex 4.6 & ex 4.8
(define (let? exp) (tagged-list? exp 'let))
(define (let-bindings exp)
(if (symbol? (cadr exp))
(caddr exp)
(cadr exp)))
(define (let-body exp)
(if (symbol? (cadr exp))
(cdddr exp)
(cddr exp)))
;; let is just lambda; to implement named lambda, I just assign the
;; original lambda to a variable and call that variable. And I wrap
;; this in another lambda to prevent the variable from leaking into
;; outer namespace.
(define (let->combination exp)
(let* ((bindings (let-bindings exp))
(lamb (make-lambda (map car bindings) (let-body exp)))
(params (map cadr bindings)))
(if (symbol? (cadr exp))
(let* ((body `((define ,(cadr exp) ,lamb)
,(append (list (cadr exp)) params)))
(wrapper (make-lambda '() (list (make-begin body)))))
(cons wrapper '()))
(cons lamb params))))
; ex 4.7
; bindings is a list of pairs, e.g. '((a 1) (b 2))
; body is a list of list, e.g. '((+ a b))
; It's sufficient to use the derived form.
(define (make-let bindings body)
(append (list 'let bindings) body))
(define (let*? exp) (tagged-list? exp 'let*))
(define (let*->nested-lets exp)
(let loop ((bindings (let-bindings exp)))
(if (null? bindings)
(sequence->exp (let-body exp))
(make-let (list (car bindings))
(list (loop (cdr bindings)))))))
; ex 4.9
(define (for? exp) (tagged-list? exp 'for))
(define (for-condition exp) (cadr exp))
(define (for-body exp) (cddr exp))
(define (for->combination exp)
(let* ([conditions (for-condition exp)]
[id (caar conditions)]
[seq (cadar conditions)]
[body (for-body exp)]
[lamb `(lambda (,id) ,(make-begin body))])
`(let iter ((seq ,seq))
(cond ((null? seq) 'done)
(else (,lamb (car seq))
(iter (cdr seq)))))))
; TODO ex 4.10