-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path8-zebra.rkt
456 lines (380 loc) · 11.3 KB
/
8-zebra.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#lang racket
(define (lookup env s)
(match env
[(list (cons name val) rest ...)
(if (equal? name s)
val
(lookup rest s))]
[(list)
(error 'unknown (~a s))]))
(define (primitive fun)
(λ (continue fail . args)
(continue fail (apply fun args))))
(define primitives
(list (cons '+ (primitive +))
(cons '- (primitive -))
(cons '/ (primitive /))
(cons '* (primitive *))
(cons '= (primitive =))
(cons '< (primitive <))
(cons '<= (primitive <=))
(cons '> (primitive >))
(cons '>= (primitive >=))
(cons 'abs (primitive abs))
(cons 'equal? (primitive equal?))
(cons 'list (primitive list))
(cons 'cons (primitive cons))
(cons 'car (primitive car))
(cons 'cdr (primitive cdr))
(cons 'null? (primitive null?))))
(define (extend-environment env names values)
(append (map cons names values) env))
(define (make-function env parameters body)
(λ (continue fail . arguments)
(define new-env (extend-environment env parameters arguments))
(eval-sequence new-env
continue
fail
body)))
(define (make-named-function env name parameters body)
(λ (continue fail . arguments)
(define new-env (extend-environment env
(list name)
(list (make-named-function env name parameters body))))
(define newer-env (extend-environment new-env parameters arguments))
(eval-sequence newer-env
continue
fail
body)))
(define (eval-arguments env continue fail args)
(match args
['() (continue fail '())]
[(list arg rest ...)
(eval-exp env
(λ (fail2 arg-val)
(eval-arguments env
(λ (fail3 rest-val)
(continue fail3 (cons arg-val rest-val)))
fail2
rest))
fail
arg)]))
(define (eval-application env continue fail fun args)
(eval-exp env
(λ (fail2 fun-val)
(eval-arguments env
(λ (fail3 args-val)
(apply fun-val continue fail3 args-val))
fail2
args))
fail
fun))
(define (eval-require env continue fail exp)
(eval-exp env
(λ (fail2 value)
(if value
(continue fail2 value)
(fail)))
fail
exp))
(define (eval-amb env continue fail exps)
(match exps
[(list) (fail)]
[(list exp rest ...)
(eval-exp env
continue
(λ () (eval-amb env continue fail rest))
exp)]))
(define (eval-sequence env continue fail terms)
(match terms
[(list exp) (eval-exp env continue fail exp)]
[(list (list 'define (list name params ...) body ...) rest ...)
(define new-env (extend-environment env
(list name)
(list (make-named-function env name params body))))
(eval-sequence new-env
continue
fail
rest)]
[(list (list 'define name exp) rest ...)
(eval-exp env
(λ (fail2 value)
(define new-env (extend-environment env (list name)(list value)))
(eval-sequence new-env continue fail2 rest))
fail
exp)]
[(list trm rest ...)
(eval-exp env
(λ (fail2 ignored)
(eval-sequence env continue fail2 rest))
fail
trm)]))
(define (eval-exp env continue fail exp)
(match exp
[(? symbol?) (continue fail (lookup env exp))]
[(? number?) (continue fail exp)]
[(? boolean?) (continue fail exp)]
[(? string?) (continue fail exp)]
[(list 'if exp then else)
(eval-exp env
(λ (fail2 value) (eval-exp env continue fail2 (if value then else)))
fail
exp)]
[(list 'require exp)
(eval-require env
continue
fail
exp)]
[(list 'amb exps ...)
(eval-amb env
continue
fail
exps)]
[(list 'quote exp) (continue fail exp)]
[(list 'begin terms ...) (eval-sequence env continue fail terms)]
[(list 'λ parameters body ...) (continue fail (make-function env parameters body))]
[(list 'lambda parameters body ...) (continue fail (make-function env parameters body))]
[(list fun args ...) (eval-application env continue fail fun args)]
[_ (error 'wat (~a exp))]))
(define (evaluate input)
(eval-exp primitives
(λ (fail res) res)
(λ () (error 'ohno))
input))
(define (evaluate* input)
(eval-exp primitives
(λ (fail res) (cons res (fail)))
(λ () '())
input))
(define (repl)
(printf "> ")
(define input (read))
(unless (eof-object? input)
(define output (evaluate input))
(printf "~a~n" output)
(repl)))
(module+ test
(require rackunit)
(check-equal?
(evaluate '(+ 1 2))
3)
(check-equal?
(evaluate '(+ 1 2 3))
6)
(check-equal?
(evaluate '(- 2 1))
1)
(check-equal?
(evaluate '(* 2 4))
8)
(check-equal?
(evaluate '(/ 8 2))
4)
(check-equal?
(evaluate '(* 2 (+ 1 (- 4 2))))
6)
(check-exn
exn:fail?
(λ ()
(eval '(foo 1 2))))
(check-equal?
(lookup (list (cons 'a 1)
(cons 'b 2))
'a)
1)
(check-equal?
(lookup (list (cons 'a 1)
(cons 'b 2))
'b)
2)
(check-equal?
(lookup (list (cons 'a 0)
(cons 'a 1)
(cons 'b 2))
'a)
0)
(check-exn
exn:fail?
(λ ()
(lookup (list (cons 'a 1)
(cons 'b 2))
'c))
0)
(check-equal?
(extend-environment (list (cons 'd 2) (cons 'e 1))
(list 'a 'b 'c)
(list 5 4 3))
(list (cons 'a 5) (cons 'b 4) (cons 'c 3) (cons 'd 2) (cons 'e 1)))
(check-equal?
(evaluate
'(begin
(define a 2)
(define b 3)
(+ a b)))
5)
(check-equal?
(evaluate
'(begin
(define a 2)
(define a 3)
(+ a a)))
6)
(check-equal?
(evaluate '((λ () (+ 2 3))))
5)
(check-equal?
(evaluate '((lambda (x y) (+ x y)) 3 4))
7)
(check-equal?
(evaluate
'((lambda ()
(define a 2)
(define b 3)
(+ a b))))
5)
(check-equal?
(evaluate
'((lambda ()
(define a 2)
(define b (lambda (c) (define a 5) (+ a c)))
(b a))))
7)
(check-equal?
(evaluate '(if #f 3 5))
5)
(check-equal?
(evaluate '(if (< 8 4) 1 0))
0)
(check-equal?
(evaluate '((λ (a b)
(if (> a (+ b b)) 3 6))
9 1))
3)
(check-equal?
(evaluate '((λ (a b)
(if (> a (+ b b)) 3 6))
9 5))
6)
(check-equal?
(eval-require primitives
(λ (x f) #t)
(λ () #f)
'(< 3 6))
#t)
(check-equal?
(eval-require primitives
(λ (x f) #t)
(λ () #f)
'(> 3 6))
#f)
(check-equal?
(evaluate
'(begin
(define a (amb 1 (- 5 3) 6 8))
(require (> a 5))
a))
6)
(check-equal?
(evaluate
'(begin
(define a (amb 1 3 5 7))
(define b (amb 2 4 3 6))
(require (= (+ a b) 9))
(list a b)))
'(3 6))
(check-equal?
(evaluate*
'(begin
(define a (amb 1 (- 5 3) 6 8))
(require (> a 5))
a))
'(6 8))
(check-equal?
(evaluate*
'(begin
(define a (amb 1 3 5 7))
(define b (amb 2 4 3 6))
(require (= (+ a b) 9))
(list a b)))
'((3 6) (5 4) (7 2)))
)
(define zebra
'(begin
(define (index-of l v)
(if (equal? (car l) v)
0
(+ 1 (index-of (cdr l) v))))
(define (neighbours? l1 v1 l2 v2)
(= 1 (abs (- (index-of l1 v1) (index-of l2 v2)))))
(define (same-index l1 v1 l2 v2)
(if (equal? (car l1) v1)
(require (equal? (car l2) v2))
(same-index (cdr l1) v1 (cdr l2) v2)))
(define (member? v l)
(if (null? l)
#f
(if (equal? (car l) v)
#t
(member? v (cdr l)))))
(define (distinct? items)
(if (null? items)
#t
(if (null? (cdr items))
#t
(if (member? (car items)(cdr items))
#f
(distinct? (cdr items))))))
(define (map f l)
(if (null? l)
'()
(cons (f (car l)) (map f (cdr l)))))
(map (λ (x) (+ x x)) '(1 2 3 4 5))
(define nat
(list
"norwegian"
(amb "english" "spanish" "japanese" "ukranian")
(amb "english" "spanish" "japanese" "ukranian")
(amb "english" "spanish" "japanese" "ukranian")
(amb "english" "spanish" "japanese" "ukranian")))
(require (distinct? nat))
(define colour
(list (amb "ivory" "green" "red" "yellow")
"blue"
(amb "ivory" "green" "red" "yellow")
(amb "ivory" "green" "red" "yellow")
(amb "ivory" "green" "red" "yellow")))
(require (distinct? colour))
(same-index nat "english" colour "red")
(require (= (index-of colour "green") (+ (index-of colour "ivory") 1)))
(define drink
(list (amb "coffee" "orange juice" "tea" "water")
(amb "coffee" "orange juice" "tea" "water")
"milk"
(amb "coffee" "orange juice" "tea" "water")
(amb "coffee" "orange juice" "tea" "water")))
(require (distinct? drink))
(same-index nat "ukranian" drink "tea")
(same-index drink "coffee" colour "green")
(define smoke
(list (amb "chesterfield" "kools" "lucky strike" "old gold" "parliament")
(amb "chesterfield" "kools" "lucky strike" "old gold" "parliament")
(amb "chesterfield" "kools" "lucky strike" "old gold" "parliament")
(amb "chesterfield" "kools" "lucky strike" "old gold" "parliament")
(amb "chesterfield" "kools" "lucky strike" "old gold" "parliament")))
(require (distinct? smoke))
(same-index smoke "kools" colour "yellow")
(same-index smoke "lucky strike" drink "orange juice")
(same-index nat "japanese" smoke "parliament")
(define pet
(list (amb "dog" "fox" "horse" "snails" "zebra")
(amb "dog" "fox" "horse" "snails" "zebra")
(amb "dog" "fox" "horse" "snails" "zebra")
(amb "dog" "fox" "horse" "snails" "zebra")
(amb "dog" "fox" "horse" "snails" "zebra")))
(require (distinct? pet))
(same-index nat "spanish" pet "dog")
(same-index smoke "old gold" pet "snails")
(require (neighbours? smoke "chesterfield" pet "fox"))
(require (neighbours? smoke "kools" pet "horse"))
(list nat colour drink smoke pet)))
(evaluate* zebra)