├── README
├── argfile.xml
├── build.xml
├── build
└── classes
│ └── default
│ └── core.clj
├── clojure-build.xml
├── lib
├── clojure-1.1.0-alpha-SNAPSHOT.jar
├── clojure-contrib.jar
└── jline-0.9.94.jar
├── manifest.mf
├── nbproject
├── build-impl.xml
├── configs
│ └── jar.properties
├── genfiles.properties
├── private
│ └── private.properties
├── project.properties
└── project.xml
├── project.clj
├── src
├── ch4
│ ├── conditionals.clj
│ ├── declarations.clj
│ ├── environment.clj
│ ├── lambdas.clj
│ ├── letting.clj
│ ├── predicates.clj
│ ├── scheme.clj
│ └── scheme_helpers.clj
├── sec1_1
│ └── sec_1_1_8.clj
├── sec1_3
│ ├── ex1_41.clj
│ ├── ex1_42.clj
│ ├── ex1_43.clj
│ └── ex1_44.clj
├── sec2_1
│ └── ex2_2.clj
└── sec2_2
│ ├── ex2_17.clj
│ ├── ex2_18.clj
│ ├── ex2_19.clj
│ ├── ex2_20.clj
│ ├── ex2_21.clj
│ ├── ex2_22.clj
│ ├── ex2_23.clj
│ ├── ex2_24.clj
│ ├── ex2_25.clj
│ ├── ex2_26.clj
│ ├── ex2_27.clj
│ ├── ex2_28.clj
│ ├── ex2_29.clj
│ ├── ex2_29_group.clj
│ ├── ex2_30.clj
│ ├── ex2_31.clj
│ ├── ex2_32.clj
│ ├── ex2_33.clj
│ ├── ex2_34.clj
│ ├── ex2_35.clj
│ ├── ex2_36.clj
│ ├── ex2_37.clj
│ ├── ex2_38.clj
│ └── ex2_39.clj
├── test
└── ch4
│ ├── environment_test.clj
│ └── scheme_test.clj
└── tools
└── repl.sh
/README:
--------------------------------------------------------------------------------
1 | book: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html#%_toc_start
2 |
3 |
4 |
--------------------------------------------------------------------------------
/argfile.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 | ]>
13 |
14 |
15 |
16 | Builds, tests, and runs the project sicp.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/build/classes/default/core.clj:
--------------------------------------------------------------------------------
1 | (comment
2 | Sample clojure source file
3 | )
4 | (ns sicp
5 | (:gen-class))
6 |
7 | (defn -main
8 | ([greetee]
9 | (println (str "Hello " greetee "!")))
10 | ([] (-main "world")))
11 |
--------------------------------------------------------------------------------
/clojure-build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 | ]>
13 |
14 |
15 |
16 |
17 | Builds, tests, and runs the project org.enclojure.ide.
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 |
32 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | <arg value = "${cljfiles}"/>
45 |
49 |
53 |
57 |
61 |
65 |
69 |
70 |
80 |
81 |
82 |
84 |
87 |
88 | &argfile;
89 |
90 |
91 |
92 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/lib/clojure-1.1.0-alpha-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deobald/sicp-clojure/fc24e5114604e7a0510dab779bbff962aac7ee7e/lib/clojure-1.1.0-alpha-SNAPSHOT.jar
--------------------------------------------------------------------------------
/lib/clojure-contrib.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deobald/sicp-clojure/fc24e5114604e7a0510dab779bbff962aac7ee7e/lib/clojure-contrib.jar
--------------------------------------------------------------------------------
/lib/jline-0.9.94.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deobald/sicp-clojure/fc24e5114604e7a0510dab779bbff962aac7ee7e/lib/jline-0.9.94.jar
--------------------------------------------------------------------------------
/manifest.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | X-COMMENT: Main-Class will be added automatically by build
3 |
4 |
--------------------------------------------------------------------------------
/nbproject/build-impl.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
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 | Must set src.dir
166 | Must set test.src.dir
167 | Must set build.dir
168 | Must set dist.dir
169 | Must set build.classes.dir
170 | Must set dist.javadoc.dir
171 | Must set build.test.classes.dir
172 | Must set build.test.results.dir
173 | Must set build.classes.excludes
174 | Must set dist.jar
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 | Must set javac.includes
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 |
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 | Must select some files in the IDE or set javac.includes
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 | To run this application from the command line without Ant, try:
463 |
464 |
465 |
466 |
467 |
468 |
469 | java -cp "${run.classpath.with.dist.jar}" ${main.class}
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 | To run this application from the command line without Ant, try:
493 |
494 | java -jar "${dist.jar.resolved}"
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 | Must select one file in the IDE or set run.class
560 |
561 |
562 |
563 | Must select one file in the IDE or set run.class
564 |
565 |
566 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 | Must select one file in the IDE or set debug.class
591 |
592 |
593 |
594 |
595 | Must select one file in the IDE or set debug.class
596 |
597 |
598 |
599 |
600 | Must set fix.includes
601 |
602 |
603 |
604 |
605 |
606 |
607 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 | Must select some files in the IDE or set javac.includes
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 | Some tests failed; see details above.
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 | Must select some files in the IDE or set test.includes
695 |
696 |
697 |
698 | Some tests failed; see details above.
699 |
700 |
701 |
706 |
707 | Must select one file in the IDE or set test.class
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
737 |
738 | Must select one file in the IDE or set applet.url
739 |
740 |
741 |
742 |
743 |
744 |
745 |
750 |
751 | Must select one file in the IDE or set applet.url
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
--------------------------------------------------------------------------------
/nbproject/configs/jar.properties:
--------------------------------------------------------------------------------
1 | main.class=sicp
2 |
--------------------------------------------------------------------------------
/nbproject/genfiles.properties:
--------------------------------------------------------------------------------
1 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
2 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
3 | nbproject/build-impl.xml.data.CRC32=19bce9e4
4 | nbproject/build-impl.xml.script.CRC32=dff996e9
5 | nbproject/build-impl.xml.stylesheet.CRC32=576378a2@1.32.1.45
6 |
--------------------------------------------------------------------------------
/nbproject/private/private.properties:
--------------------------------------------------------------------------------
1 | jaxbwiz.endorsed.dirs=/Applications/NetBeans/NetBeans 6.8.app/Contents/Resources/NetBeans/ide12/modules/ext/jaxb/api
2 | user.properties.file=/Users/sdeobald/.netbeans/6.8/build.properties
3 |
--------------------------------------------------------------------------------
/nbproject/project.properties:
--------------------------------------------------------------------------------
1 | application.title=sicp
2 | application.vendor=enclojure
3 | build.classes.dir=${build.dir}/classes
4 | build.classes.excludes=**/*.java,**/*.form
5 | # This directory is removed when the project is cleaned:
6 | build.dir=build
7 | build.generated.dir=${build.dir}/generated
8 | build.generated.sources.dir=${build.dir}/generated-sources
9 | # Only compile against the classpath explicitly listed here:
10 | build.sysclasspath=ignore
11 | build.test.classes.dir=${build.dir}/test/classes
12 | build.test.results.dir=${build.dir}/test/results
13 | debug.classpath=\
14 | ${run.classpath}
15 | debug.test.classpath=\
16 | ${run.test.classpath}
17 | # This directory is removed when the project is cleaned:
18 | dist.dir=dist
19 | dist.jar=${dist.dir}/sicp.jar
20 | dist.javadoc.dir=${dist.dir}/javadoc
21 | excludes=
22 | includes=**
23 | jar.compress=false
24 | javac.classpath=\
25 | ${libs.Clojure-1.0.0.classpath}
26 | # Space-separated list of extra javac options
27 | javac.compilerargs=
28 | javac.deprecation=false
29 | javac.source=1.5
30 | javac.target=1.5
31 | javac.test.classpath=\
32 | ${javac.classpath}:\
33 | ${build.classes.dir}:\
34 | ${libs.junit.classpath}:\
35 | ${libs.junit_4.classpath}
36 | javadoc.additionalparam=
37 | javadoc.author=false
38 | javadoc.encoding=${source.encoding}
39 | javadoc.noindex=false
40 | javadoc.nonavbar=false
41 | javadoc.notree=false
42 | javadoc.private=false
43 | javadoc.splitindex=true
44 | javadoc.use=true
45 | javadoc.version=false
46 | javadoc.windowtitle=
47 | jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
48 | main.class=sicp
49 | manifest.file=manifest.mf
50 | meta.inf.dir=${src.dir}/META-INF
51 | platform.active=default_platform
52 | run.classpath=\
53 | ${javac.classpath}:\
54 | ${build.classes.dir}
55 | run.test.classpath=\
56 | ${javac.test.classpath}:\
57 | ${build.test.classes.dir}
58 | source.encoding=UTF-8
59 | src.dir=src
60 | test.src.dir=test
61 |
--------------------------------------------------------------------------------
/nbproject/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.netbeans.modules.java.j2seproject
4 |
5 |
6 | sicp
7 | 1.6.5
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 |
2 | (defproject sicp "1.0.0-SNAPSHOT"
3 | :description "Solutions to SICP"
4 | :dependencies [[org.clojure/clojure "1.2.0-master-SNAPSHOT"]
5 | [org.clojure/clojure-contrib "1.2.0-master-SNAPSHOT"]])
6 |
--------------------------------------------------------------------------------
/src/ch4/conditionals.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.conditionals
3 | (:use ch4.scheme-helpers
4 | ch4.predicates
5 | ch4.declarations))
6 |
7 | (defn if-predicate [exp] (cadr exp))
8 |
9 | (defn if-consequent [exp] (caddr exp))
10 |
11 | (defn if-alternative [exp]
12 | (if (not (nil? (cdddr exp)))
13 | (cadddr exp)
14 | 'false))
15 |
16 | (defn make-if [predicate consequent alternative]
17 | (list 'if predicate consequent alternative))
18 |
19 | (defn extended-cond? [clause]
20 | (and (list? clause)
21 | (> (count clause) 2)
22 | (= (second clause) '=>)))
23 |
24 | (defn extended-cond-test [clause]
25 | (first clause))
26 |
27 | (defn extended-cond-recipient [clause]
28 | (nth clause 2))
29 |
30 | (defn cond? [exp] (tagged-list? exp 'cond))
31 |
32 | (defn cond-clauses [exp] (cdr exp))
33 |
34 | (defn cond-predicate [clause] (car clause))
35 |
36 | (defn cond-else-clause? [clause]
37 | (= (cond-predicate clause) 'else))
38 |
39 | (defn cond-actions [clause] (cdr clause))
40 |
41 | (declare expand-clauses)
42 |
43 | (defn cond->if [exp]
44 | (expand-clauses (cond-clauses exp)))
45 |
46 | (defn expand-clauses [clauses]
47 | (if (null? clauses)
48 | 'false
49 | (let [first-clause (car clauses)
50 | rest-clauses (cdr clauses)]
51 | (cond (cond-else-clause? first-clause)
52 | (if (null? rest-clauses)
53 | (sequence->exp (cond-actions first-clause))
54 | (Error. (str "ELSE clause isn't last -- COND->IF"
55 | clauses)))
56 | (extended-cond? first-clause)
57 | (make-if (extended-cond-test first-clause)
58 | (list
59 | (extended-cond-recipient first-clause)
60 | (extended-cond-test first-clause))
61 | (expand-clauses rest-clauses))
62 | :else
63 | (make-if (cond-predicate first-clause)
64 | (sequence->exp (cond-actions first-clause))
65 | (expand-clauses rest-clauses))))))
66 |
--------------------------------------------------------------------------------
/src/ch4/declarations.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.declarations
3 | (:use ch4.scheme-helpers
4 | ch4.predicates))
5 |
6 | (defn make-begin [xs] (cons 'begin xs))
7 |
8 | (defn make-definition [fn-name parameters body]
9 | (list 'define (cons fn-name parameters) body))
10 |
11 | (defn sequence->exp [xs]
12 | (cond (null? xs) xs
13 | (last-exp? xs) (first-exp xs)
14 | :else (make-begin xs)))
15 |
--------------------------------------------------------------------------------
/src/ch4/environment.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.environment
3 | (:use ch4.scheme-helpers))
4 |
5 | (defn enclosing-environment [env] (rest env))
6 |
7 | (defn first-frame [env] (car env))
8 |
9 | (def the-empty-environment '())
10 |
11 | (defn make-frame [variables values]
12 | (atom (zipmap variables values)))
13 |
14 | (defn frame-variables [frame] (keys @frame))
15 |
16 | (defn frame-values [frame] (vals @frame))
17 |
18 | (defn add-binding-to-frame! [var val frame]
19 | (swap! frame assoc var val))
20 |
21 | (defn extend-environment [vars vals base-env]
22 | (if (= (count vars) (count vals))
23 | (cons (make-frame vars vals) base-env)
24 | (if (< (count vars) (count vals))
25 | (Error. (str "Too many arguments supplied " vars vals))
26 | (Error. (str "Too few arguments supplied " vars vals)))))
27 |
28 | (defn copy-environment [e]
29 | (doall (map #(atom @%) e)))
30 |
31 | (defn environments-equal? [x y]
32 | (reduce #(and %1 %2) true (map #(= @%1 @%2) x y)))
33 |
34 | (defn lookup-variable-value [variable env]
35 | (letfn [(env-loop [env]
36 | (letfn [(scan [frame]
37 | (if (contains? frame variable)
38 | (let [value (get frame variable)]
39 | (if (= value '*unassigned*)
40 | (Error. (str "Unassigned variable " variable))
41 | value))
42 | (env-loop (enclosing-environment env))))]
43 | (if (= env the-empty-environment)
44 | (Error. (str "Unbound variable " variable))
45 | (let [frame (first-frame env)]
46 | (scan @frame)))))]
47 | (env-loop env)))
48 |
49 |
50 | (defn set-variable-value! [variable value env]
51 | (letfn [(env-loop [env]
52 | (letfn [(scan [frame]
53 | (if (contains? @frame variable)
54 | (swap! frame assoc variable value)
55 | (env-loop (enclosing-environment env))))]
56 | (if (= env the-empty-environment)
57 | (Error. (str "Unbound variable -- SET! " variable))
58 | (scan (first-frame env)))))]
59 | (env-loop env)))
60 |
61 | (defn define-variable! [variable value env]
62 | (swap! (first-frame env) assoc variable value))
63 |
64 | (defn unbind-variable! [variable env]
65 | (swap! (first-frame env) dissoc variable))
66 |
67 |
--------------------------------------------------------------------------------
/src/ch4/lambdas.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.lambdas
3 | ;(:require )
4 | ;(:use )
5 | ;(:import )
6 | )
7 |
8 |
9 | (defn lambda-parameters [exp] (second exp))
10 |
11 | (defn lambda-body [exp] (rest (rest exp)))
12 |
13 | (defn make-lambda [parameters body]
14 | (cons 'lambda (cons parameters body)))
15 |
16 |
--------------------------------------------------------------------------------
/src/ch4/letting.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.letting
3 | (:use ch4.predicates
4 | ch4.declarations
5 | ch4.lambdas))
6 |
7 | (defn let? [exp]
8 | (tagged-list? exp 'let))
9 |
10 | (defn named-let? [exp]
11 | (symbol? (second exp)))
12 |
13 | (defn let-body [exp]
14 | (if (named-let? exp)
15 | (nth exp 3)
16 | (nth exp 2)))
17 |
18 | (defn make-let [clauses body]
19 | (list 'let clauses body))
20 |
21 | (defn let-variables [exp]
22 | (if (named-let? exp)
23 | (map first (nth exp 2))
24 | (map first (second exp))))
25 |
26 | (defn let-values [exp]
27 | (if (named-let? exp)
28 | (map second (nth exp 2))
29 | (map second (second exp))))
30 |
31 | (defn let-name [exp]
32 | (second exp))
33 |
34 | (defn let*? [exp]
35 | (tagged-list? exp 'let*))
36 |
37 | (defn let*->nested-lets [exp]
38 | (let [let-clauses (reverse (second exp))
39 | body (let-body exp)]
40 | (reduce #(make-let (list %2) %1) body let-clauses)))
41 |
42 | ; define function
43 | ; eval function with arguments
44 | (defn let->combination [exp]
45 | (let [parameters (let-variables exp)
46 | args (let-values exp)
47 | body (let-body exp)]
48 | (if (named-let? exp)
49 | (sequence->exp
50 | (list
51 | (make-definition (let-name exp)
52 | parameters
53 | body)
54 | (cons
55 | (let-name exp)
56 | args)))
57 | (cons
58 | (make-lambda (let-variables exp)
59 | (list (let-body exp)))
60 | (let-values exp)))))
61 |
--------------------------------------------------------------------------------
/src/ch4/predicates.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.predicates
3 | (:use ch4.scheme-helpers))
4 |
5 |
6 | (defn first-exp [xs] (car xs))
7 |
8 | (defn rest-exps [xs] (cdr xs))
9 |
10 | (defn tagged-list? [exp tag]
11 | (if (seq? exp)
12 | (= (first exp) tag)
13 | false))
14 |
15 | (defn last-exp? [xs] (null? (cdr xs)))
16 |
17 | (declare last-exp? first-exp rest-exps)
18 |
19 | (defn begin? [exp] (tagged-list? exp 'begin))
20 |
21 | (defn quoted? [exp]
22 | (tagged-list? exp 'quote))
23 |
24 | (defn pair? [x] (seq? x))
25 |
26 | (defn application? [exp] (pair? exp))
27 |
28 | (defn definition? [exp]
29 | (tagged-list? exp 'define))
30 |
31 | (defn assignment? [exp]
32 | (tagged-list? exp 'set!))
33 |
34 | (defn variable? [exp]
35 | (or (symbol? exp)
36 | (= 'true exp)
37 | (= 'false exp)))
38 |
39 | (defn if? [exp] (tagged-list? exp 'if))
40 |
41 | (defn lambda? [exp] (tagged-list? exp 'lambda))
42 |
43 | (defn self-evaluating? [exp]
44 | (or (number? exp)
45 | (string? exp)
46 | (and (seq? exp) (self-evaluating? (first exp)))))
47 |
--------------------------------------------------------------------------------
/src/ch4/scheme.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.scheme
3 | (:use ch4.scheme-helpers
4 | ch4.environment
5 | ch4.predicates
6 | ch4.declarations
7 | ch4.lambdas
8 | ch4.letting
9 | ch4.conditionals))
10 |
11 | (declare execute-application
12 | primitive-procedure-names
13 | primitive-procedure-objects)
14 |
15 | (declare my-eval
16 | my-apply
17 | analyze)
18 |
19 | (declare no-operands?
20 | first-operand
21 | rest-operands)
22 |
23 | ; Exercise 4.1
24 | (defn list-of-values [exps env]
25 | (if (no-operands? exps)
26 | '()
27 | (let [left (my-eval (first-operand exps) env)
28 | right (list-of-values (rest-operands exps) env)]
29 | (cons left right))))
30 | ; Above function imposes a left to right ordering. If the
31 | ; assignments inside of let where switched it would be right
32 | ; to left
33 |
34 | (defn eval-if [exp env]
35 | (if (my-eval (if-predicate exp) env)
36 | (my-eval (if-consequent exp) env)
37 | (my-eval (if-alternative exp) env)))
38 |
39 | (defn eval-sequence [exps env]
40 | (cond (last-exp? exps) (my-eval (first-exp exps) env)
41 | :else (do (my-eval (first-exp exps) env)
42 | (eval-sequence (rest-exps exps) env))))
43 |
44 | (declare assignment-variable assignment-value)
45 |
46 | (defn eval-assignment [exp env]
47 | (set-variable-value! (assignment-variable exp)
48 | (my-eval (assignment-value exp) env)
49 | env)
50 | 'ok)
51 |
52 | (declare definition-variable definition-value)
53 |
54 | (defn eval-definition [exp env]
55 | (define-variable!
56 | (definition-variable exp)
57 | (my-eval (definition-value exp) env)
58 | env)
59 | 'ok)
60 |
61 | (defn text-of-quotation [exp] (cadr exp))
62 |
63 | (defn assignment-variable [exp] (second exp))
64 |
65 | (defn assignment-value [exp] (nth exp 2))
66 |
67 | (defn definition-variable [exp]
68 | (if (symbol? (second exp))
69 | (second exp)
70 | (first (first (rest exp)))))
71 |
72 | (defn definition-value [exp]
73 | (if (symbol? (second exp))
74 | (nth exp 2)
75 | (make-lambda (rest (first (rest exp))) ; formal parameters
76 | (rest (rest exp))))) ; body
77 |
78 | (defn begin-actions [exp] (cdr exp))
79 |
80 | (defn operator [exp] (car exp))
81 |
82 | (defn operands [exp] (cdr exp))
83 |
84 | (defn no-operands? [ops] (null? ops))
85 |
86 | (defn first-operand [ops] (car ops))
87 |
88 | (defn rest-operands [ops] (cdr ops))
89 |
90 | (declare scan-out-defines)
91 | (defn make-procedure [parameters body env]
92 | (list 'procedure parameters (scan-out-defines body) env))
93 |
94 | (defn compound-procedure? [p]
95 | (tagged-list? p 'procedure))
96 |
97 | (defn procedure-parameters [p] (cadr p))
98 |
99 | (defn procedure-body [p] (caddr p))
100 |
101 | (defn procedure-environment [p] (cadddr p))
102 |
103 | (def primitive-procedures
104 | (list (list 'car car)
105 | (list 'cdr cdr)
106 | (list 'cadr cadr)
107 | (list 'cons cons)
108 | (list 'null? null?)
109 | (list '+ +)
110 | (list '- -)
111 | (list '* *)
112 | (list '/ /)
113 | (list '= =)
114 | (list '> >)
115 | (list '< <)
116 | (list 'and (fn [& xs] (reduce #(and %1 %2) true xs)))
117 | (list 'or (fn [& xs] (reduce #(or %1 %2) false xs)))))
118 |
119 | (defn primitive-procedure-names []
120 | (map car primitive-procedures))
121 |
122 | (defn primitive-procedure-objects []
123 | (map (fn [proc] (list 'primitive (cadr proc)))
124 | primitive-procedures))
125 |
126 | (defn setup-environment []
127 | (let [initial-env
128 | (extend-environment (primitive-procedure-names)
129 | (primitive-procedure-objects)
130 | the-empty-environment)]
131 | (define-variable! 'true true initial-env)
132 | (define-variable! 'false false initial-env)
133 | (define-variable! 'nil nil initial-env)
134 | initial-env))
135 |
136 | (def the-global-environment (setup-environment))
137 |
138 | (defn reset-global-environment []
139 | (def the-global-environment (setup-environment)))
140 |
141 | ; Exercise 4.13
142 | (defn unbind? [exp]
143 | (tagged-list? exp 'make-unbound!))
144 |
145 | (defn eval-unbind [exp env]
146 | (unbind-variable! (second exp) env)
147 | 'ok)
148 |
149 | (defn primitive-procedure? [proc]
150 | (tagged-list? proc 'primitive))
151 |
152 | (defn primitive-implementation [proc] (cadr proc))
153 |
154 | (defn apply-primitive-procedure [proc args]
155 | (apply (primitive-implementation proc) args))
156 |
157 | (defn execute-application [proc args]
158 | (cond (primitive-procedure? proc)
159 | (apply-primitive-procedure proc args)
160 | (compound-procedure? proc)
161 | ((procedure-body proc)
162 | (extend-environment (procedure-parameters proc)
163 | args
164 | (procedure-environment proc)))
165 | :else
166 | (Error. (str
167 | "Unknown procedure type -- EXECUTE-APPLICATION"
168 | proc))))
169 |
170 | (defn is-define? [e]
171 | (and (seq? e)
172 | (tagged-list? e 'define)))
173 |
174 | (defn find-defines [exp]
175 | (filter is-define? exp))
176 |
177 | (defn defined-variables [defs]
178 | (map second defs))
179 |
180 | (defn defined-values [defs]
181 | (map #(nth % 2) defs))
182 |
183 | (defn non-defines [exp]
184 | (remove is-define? exp))
185 |
186 | (defn scan-out-defines [exp]
187 | (let [defs (find-defines exp)]
188 | (if (zero? (count defs))
189 | exp
190 | (let [variables (defined-variables defs)
191 | values (defined-values defs)
192 | body (nth (non-defines exp) 2)
193 | vars (second (non-defines exp))]
194 | (list 'lambda
195 | vars
196 | (cons 'let
197 | (cons (map #(list % (quote (quote *unassigned*))) variables)
198 | (concat (map
199 | #(list 'set! %1 %2)
200 | variables
201 | values)
202 | (list body)))))))))
203 |
204 | ; Exercise 4.20
205 | (defn letrec? [exp]
206 | (tagged-list? exp 'letrec))
207 |
208 | (defn letrec->let [exp]
209 | (let [fns (second exp)
210 | fn-names (map first fns)
211 | fn-vals (map second fns)
212 | body (nth exp 2)]
213 | (make-let
214 | (map #(list % ''*unassigned*) fn-names)
215 | (make-begin
216 | (concat
217 | (map #(list 'set! %1 %2) fn-names fn-vals)
218 | (list body))))))
219 |
220 | (defn my-eval [exp env]
221 | (cond (self-evaluating? exp) exp
222 | (variable? exp) (lookup-variable-value exp env)
223 | (quoted? exp) (text-of-quotation exp)
224 | (assignment? exp) (eval-assignment exp env)
225 | (unbind? exp) (eval-unbind exp env)
226 | (definition? exp) (eval-definition exp env)
227 | (if? exp) (eval-if exp env)
228 | (lambda? exp)
229 | (make-procedure (lambda-parameters exp)
230 | (lambda-body exp)
231 | env)
232 | (begin? exp)
233 | (eval-sequence (begin-actions exp) env)
234 | (cond? exp) (my-eval (cond->if exp) env)
235 | (let? exp) (my-eval (let->combination exp) env)
236 | (let*? exp) (my-eval (let*->nested-lets exp) env)
237 | (letrec? exp) (my-eval (letrec->let exp) env)
238 | (application? exp)
239 | (my-apply (my-eval (operator exp) env)
240 | (list-of-values (operands exp) env))
241 | :else (Error. (str "Unknown expression type -- EVAL " exp))))
242 |
243 | (defn my-apply [procedure arguments]
244 | (cond (primitive-procedure? procedure)
245 | (apply-primitive-procedure procedure arguments)
246 | (compound-procedure? procedure)
247 | (eval-sequence
248 | (procedure-body procedure)
249 | (extend-environment
250 | (procedure-parameters procedure)
251 | arguments
252 | (procedure-environment procedure)))
253 | :else (Error. (str "Unknown procedure type -- APPLY " procedure))))
254 |
255 | (defn interpret [exp]
256 | (my-eval exp the-global-environment))
--------------------------------------------------------------------------------
/src/ch4/scheme_helpers.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.scheme-helpers)
3 |
4 | (defn car [x] (first x))
5 | (defn cdr [x] (next x))
6 | (defn cadr [x] (second x))
7 | (defn caddr [x] (first (next (next x))))
8 | (defn cdddr [x] (next (next (next x))))
9 | (defn caddr [x] (first (next (next x))))
10 | (defn cadddr [x] (first (next (next (next x)))))
11 | (defn null? [x] (nil? x))
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/sec1_1/sec_1_1_8.clj:
--------------------------------------------------------------------------------
1 | (ns sec1-1.sec-1-1-8)
2 |
3 | ;; from: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1.8
4 | ;; "Internal definitions and block structure"
5 |
6 | (defn sqrt [x]
7 | (let [square (fn [side] (* side side))
8 | average (fn [a b] (/ (+ a b) 2))
9 | good-enough? (fn [guess] (< (Math/abs (- (square guess) x)) 0.001))
10 | improve (fn [guess] (average guess (/ x guess)))
11 | sqrt-iter (fn sqrt-iter [guess] (if (good-enough? guess) guess (sqrt-iter (improve guess))))]
12 | (sqrt-iter 1.0)))
13 |
14 |
--------------------------------------------------------------------------------
/src/sec1_3/ex1_41.clj:
--------------------------------------------------------------------------------
1 | (ns sec1-3.ex1-41)
2 |
3 | (defn incr [num]
4 | (+ num 1))
5 |
6 | (defn dub [proc]
7 | #(proc (proc %)))
8 |
9 | (((dub (dub dub)) incr) 5)
10 | ; => 21
11 |
--------------------------------------------------------------------------------
/src/sec1_3/ex1_42.clj:
--------------------------------------------------------------------------------
1 | (ns sec1-3.ex1-42)
2 |
3 | (defn incr [num]
4 | (+ num 1))
5 |
6 | (defn square [num]
7 | (* num num))
8 |
9 | (defn compose [fn1 fn2]
10 | #(fn1 (fn2 %)))
11 |
12 | ((compose square incr) 6)
13 |
14 |
--------------------------------------------------------------------------------
/src/sec1_3/ex1_43.clj:
--------------------------------------------------------------------------------
1 | (ns sec1-3.ex1-43)
2 |
3 | (defn square [num]
4 | (* num num))
5 |
6 | (defn compose [f g]
7 | #(f (g %)))
8 |
9 | (defn repeated-inside [original-f f times]
10 | (if (= times 1)
11 | f
12 | (recur original-f (comp original-f f) (dec times))))
13 |
14 | (defn repeated [f times]
15 | (repeated-inside f f times))
16 |
17 | ((repeated square 2) 5)
18 | ; => 625
19 |
--------------------------------------------------------------------------------
/src/sec1_3/ex1_44.clj:
--------------------------------------------------------------------------------
1 | (ns sec1-3.ex1-44
2 | (:use [sec1-3.ex1-43 :only (repeated)]))
3 |
4 | (defn sq [num]
5 | (* num num))
6 |
7 | (defn avg [coll]
8 | (/ (apply + coll) (count coll)))
9 |
10 | (defn smooth [f]
11 | (let [dx 0.00001]
12 | #(avg [(f (- % dx)) (f %) (f (+ % dx))])))
13 |
14 | (defn smoothed [f times]
15 | (let [done (repeated smooth times)]
16 | (done f )))
17 |
18 | (def gaz repeated)
19 |
20 | ((smoothed sq 2) 6)
--------------------------------------------------------------------------------
/src/sec2_1/ex2_2.clj:
--------------------------------------------------------------------------------
1 | (ns sec2-1.ex2-2)
2 |
3 | (defn make-point [x y]
4 | {:x x :y y})
5 |
6 | (defn make-segment [start end]
7 | {:start start :end end})
8 |
9 | (defn print-point [p]
10 | (print "(")
11 | (print (:x p))
12 | (print ", ")
13 | (print (:y p))
14 | (print ")"))
15 |
16 | (defn print-segment [segment]
17 | (print newline)
18 | (print-point (:start segment))
19 | (print " - ")
20 | (print-point (:end segment)))
21 |
22 | (defn midpoint-segment [segment]
23 | (let [midpoint-x (average (:x (:start segment)) (:x (:end segment)))
24 | midpoint-y (average (:y (:start segment)) (:y (:end segment)))]
25 | (make-point midpoint-x midpoint-y)))
26 |
27 | (def steves-segment
28 | make-segment (make-point 2 2) (make-point 10 10))
29 |
30 | (print-segment steves-segment)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_17.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_17
2 | (:use clojure.test))
3 |
4 | (defn last-pair [l]
5 | (if (= (count l) 1)
6 | l
7 | (recur (rest l))))
8 |
9 | (deftest should-retrieve-34-as-last-item-in-list
10 | (is (= '(34) (last-pair '(23 72 149 34)))))
11 |
12 | (run-all-tests #"ex.*")
--------------------------------------------------------------------------------
/src/sec2_2/ex2_18.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_18
2 | (:use clojure.test))
3 |
4 | (defn ireverse [l]
5 | (let [shift (fn [original accum]
6 | (if (empty? original)
7 | accum
8 | (recur (rest original) (conj accum (first original)))))]
9 | (shift l '())))
10 |
11 | (deftest should-return-a-list-in-reverse-order
12 | (is (= (list 25 16 9 4 1) (ireverse (list 1 4 9 16 25)))))
13 |
14 | (run-all-tests #"ex.*")
15 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_19.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_19
2 | (:use clojure.test))
3 |
4 | (defn first-denomination [x]
5 | (first x))
6 |
7 | (defn except-first-denomination [x]
8 | (rest x))
9 |
10 | (defn no-more? [x]
11 | (empty? x))
12 |
13 | (defn cc [amount coin-values]
14 | (cond (= amount 0) 1
15 | (or (< amount 0) (no-more? coin-values)) 0
16 | :else
17 | (+ (cc amount
18 | (except-first-denomination coin-values))
19 | (cc (- amount (first-denomination coin-values))
20 | coin-values))))
21 |
22 | (def us-coins (list 50 25 10 5 1))
23 | (def uk-coins (list 100 50 20 10 5 2 1 0.5))
24 |
25 | (deftest should-find-100-cents-can-be-counted-292-ways-with-us-coins
26 | (is (= 292 (cc 100 us-coins))))
27 |
28 | (deftest should-find-50-pence-can-be-counted-6149-ways-with-uk-coins
29 | (is (= 6149 (cc 50 uk-coins))))
30 |
31 | (run-all-tests #"ex.*")
32 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_20.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_20
2 | (:use clojure.test))
3 |
4 | (defn same-parity [& nums]
5 | (if (even? (first nums))
6 | (filter even? nums)
7 | (filter odd? nums)))
8 |
9 | (deftest should-return-all-odd-numbers-given-when-list-begins-with-an-odd-number
10 | (is (= '(1 3 5 7) (same-parity 1 2 3 4 5 6 7))))
11 |
12 | (deftest should-return-all-even-numbers-given-when-list-begins-with-an-even-number
13 | (is (= '(2 4 6) (same-parity 2 3 4 5 6 7))))
14 |
15 | (run-all-tests #"ex.*")
16 |
17 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_21.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_21
2 | (:use clojure.test))
3 |
4 | (defn square [number]
5 | (* number number))
6 |
7 | (defn square-list-1 [items]
8 | (if (empty? items)
9 | nil
10 | (cons (square (first items))
11 | (square-list-1 (rest items)))))
12 |
13 | (defn square-list-2 [items]
14 | (map square items))
15 |
16 | (deftest should-square-each-item-in-the-list-1
17 | (is (= '(1 4 9 16) (square-list-1 '(1 2 3 4)))))
18 |
19 | (deftest should-square-each-item-in-the-list-2
20 | (is (= '(1 4 9 16) (square-list-2 '(1 2 3 4)))))
21 |
22 | (run-all-tests #"ex.*")
23 |
24 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_22.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_22)
2 |
3 | ; the first attempt removes items front-to-back, but adds them to the answer back-to-front
4 | ; first attempt (via jake):
5 |
6 | (defn square [x] (* x x))
7 |
8 | (defn square-list [items]
9 | (letfn [(iter [things answer]
10 | (if (empty? things)
11 | answer
12 | (recur (rest things)
13 | (cons (square (first things))
14 | answer))))]
15 | (iter items nil)))
16 |
17 | (square-list (list 1 2 3 4))
18 |
19 |
20 | ; the second attempt creates a nested list of lists
21 | ; the clojure behavioural equivalent of scheme 'cons' is 'list'
22 | ; second attempt (via jake):
23 |
24 | (defn square-list [items]
25 | (letfn [(iter [things answer]
26 | (if (empty? things)
27 | answer
28 | (recur (rest things)
29 | (list answer (square (first things))))))]
30 | (iter items nil)))
31 |
32 | (square-list (list 1 2 3 4))
33 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_23.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_23)
2 |
3 | (defn for-each [fn items]
4 | (fn (first items))
5 | (if (empty? items)
6 | true
7 | (recur fn (rest items))))
8 |
9 | (for-each #(println %) '(57 321 88))
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_24.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_24)
2 |
3 | (list 1 (list 2 (list 3 4)))
4 | ; (1 (2 (3 4)))
5 |
6 | '(1 (2 (3 4)))
7 | ; (1 (2 (3 4)))
8 |
9 | ; (1 (2 (3 4)))
10 | ; / \
11 | ; 1 (2 (3 4))
12 | ; / \
13 | ; 2 (3 4)
14 | ; / \
15 | ; 3 4
16 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_25.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_25)
2 |
3 | (def example1 '(1 3 (5 7) 9))
4 |
5 | (def example2 '((7)))
6 |
7 | (def example3 '(1 (2 (3 (4 (5 (6 7)))))))
8 |
9 | (println
10 | (first (rest (first (rest (rest example1))))))
11 |
12 | (println
13 | (first (first example2)))
14 |
15 | (println
16 | (first (rest (first (rest (first (rest (first (rest (first (rest (first (rest example3)))))))))))))
17 |
18 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_26.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_26)
2 |
3 | (def x (list 1 2 3))
4 |
5 | (def y (list 4 5 6))
6 |
7 | ; from 2.2.1
8 | (defn append [list1 list2]
9 | (if (empty? list1)
10 | list2
11 | (cons (first list1) (append (rest list1) list2))))
12 |
13 | (append x y)
14 | ; (1 2 3 4 5 6)
15 |
16 | (cons x y)
17 | ; ((1 2 3) 4 5 6)
18 |
19 | (list x y)
20 | ; ((1 2 3) (4 5 6))
21 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_27.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_27
2 | (:use clojure.test))
3 |
4 | (defn deep-reverse [x]
5 | (cond (nil? x) nil
6 | (not (seq? x)) x
7 | :default (map deep-reverse (reverse x))))
8 |
9 | (deftest should-reverse-items-in-sub-lists-as-well-as-the-list-itself
10 | (is (= '((4 3) (2 1)) (deep-reverse '((1 2) (3 4))))))
11 |
12 | (run-all-tests #"ex.*")
13 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_28.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_28
2 | (:use clojure.test))
3 |
4 | (def x '((1 2) (3 4)))
5 |
6 | (defn append [list1 list2]
7 | (if (empty? list1)
8 | list2
9 | (cons (first list1) (append (rest list1) list2))))
10 |
11 | (defn fringe [x]
12 | (cond (nil? x) nil
13 | (not (seq? x)) (list x)
14 | (empty? x) '()
15 | :default (append (fringe (first x)) (fringe (rest x)))))
16 |
17 | (deftest should-create-a-list-containing-all-leaves-from-left-to-right
18 | (is (= '(1 2 3 4) (fringe x))))
19 |
20 | (run-all-tests #"ex.*")
21 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_29.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_29
2 | (:use clojure.test))
3 |
4 | (defn make-mobile [left right]
5 | (list left right))
6 |
7 | (defn make-branch [length structure]
8 | (list length structure))
9 |
10 | ; a. Write the corresponding selectors left-branch and right-branch, which return the branches of the mobile, and
11 | ; branch-length and branch-structure which return the components of a branch.
12 |
13 | (defn left-branch [mobile]
14 | (first mobile))
15 |
16 | (defn right-branch [mobile]
17 | (first
18 | (rest mobile)))
19 |
20 | (defn branch-length [branch]
21 | (first branch))
22 |
23 | (defn branch-structure [branch]
24 | (first
25 | (rest branch)))
26 |
27 | ; b. Using those selectors, define a procedure total-weight that returns the total weight of a mobile.
28 |
29 | (def total-weight)
30 |
31 | (defn branch-weight [branch]
32 | (let [structure (branch-structure branch)]
33 | (if (number? structure)
34 | structure
35 | (total-weight structure))))
36 |
37 | (defn total-weight [mobile]
38 | (+ (branch-weight (left-branch mobile))
39 | (branch-weight (right-branch mobile))))
40 |
41 | (deftest should-weigh-a-simple-mobile
42 | (let [left (make-branch 2 3)
43 | right (make-branch 2 5)]
44 | (is (= 8 (total-weight (make-mobile left right))))))
45 |
46 | (deftest should-weigh-a-complex-mobile
47 | (let [left-1 (make-branch 2 3)
48 | left-2 (make-branch 2 5)
49 | left-mobile (make-mobile left-1 left-2)
50 | left (make-branch 2 left-mobile)
51 | right (make-branch 2 9)]
52 | (is (= 17 (total-weight (make-mobile left right))))))
53 |
54 | ; c. Design a predicate that tests whether a binary mobile is balanced.
55 |
56 | (defn branch-torque [branch]
57 | (* (branch-weight branch) (branch-length branch)))
58 |
59 | (defn balanced? [mobile]
60 | (= (branch-torque (left-branch mobile))
61 | (branch-torque (right-branch mobile))))
62 |
63 | (deftest a-mobile-is-balanced-if-both-branches-have-equal-torque
64 | (let [left (make-branch 2 3)
65 | right (make-branch 2 3)
66 | mobile (make-mobile left right)]
67 | (is (balanced? mobile))))
68 |
69 | (deftest a-mobile-is-not-balanced-if-one-branch-has-more-torque-than-the-other
70 | (let [left (make-branch 2 3)
71 | right (make-branch 2 4)
72 | mobile (make-mobile left right)]
73 | (is (not (balanced? mobile)))))
74 |
75 | ; d. Suppose we change the constructors to use 'cons' (scheme). How much do you need to change the programs
76 | ; to convert to the new representation?
77 |
78 | ; answer: only the selectors need to change, given a scheme-style cons. (car/cdr vs. car/cadr)
79 |
80 | (run-all-tests #"ex.*")
81 |
82 |
83 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_29_group.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_29_group
2 | (:use clojure.test))
3 |
4 | (defn make-mobile [left right]
5 | (list left right))
6 |
7 | (defn make-branch [length structure]
8 | (list length structure))
9 |
10 | ; a. Write the corresponding selectors left-branch and right-branch, which return the branches of the mobile, and
11 | ; branch-length and branch-structure which return the components of a branch.
12 |
13 | (defn left-branch [mobile]
14 | (first mobile))
15 |
16 | (defn right-branch [mobile]
17 | (first
18 | (rest mobile)))
19 |
20 | (defn branch-length [branch]
21 | (first branch))
22 |
23 | (defn branch-structure [branch]
24 | (first
25 | (rest branch)))
26 |
27 | ; b. Using those selectors, define a procedure total-weight that returns the total weight of a mobile.
28 |
29 | (defn total-weight [mobile]
30 | (if (seq? (fnext mobile)) (+ (total-weight first) (total-weight fnext))
31 | (fnext mobile)))
32 |
33 | (deftest should-weigh-an-ultra-simple-mobile
34 | (is (= 1 (total-weight '(3 1)))))
35 |
36 | (deftest should-weigh-a-simple-mobile
37 | (let [left (make-branch 2 3)
38 | right (make-branch 2 5)]
39 | (is (= 8 (total-weight (make-mobile left right))))))
40 |
41 | (deftest should-weigh-a-complex-mobile
42 | (let [left-1 (make-branch 2 3)
43 | left-2 (make-branch 2 5)
44 | left-mobile (make-mobile left-1 left-2)
45 | left (make-branch 2 left-mobile)
46 | right (make-branch 2 9)]
47 | (is (= 17 (total-weight (make-mobile left right))))))
48 |
49 | ; c. Design a predicate that tests whether a binary mobile is balanced.
50 |
51 |
52 |
53 | ;(deftest a-mobile-is-balanced-if-both-branches-have-equal-torque
54 | ; (let [left (make-branch 2 3)
55 | ; right (make-branch 2 3)
56 | ; mobile (make-mobile left right)]
57 | ; (is (balanced? mobile))))
58 | ;
59 | ;(deftest a-mobile-is-not-balanced-if-one-branch-has-more-torque-than-the-other
60 | ; (let [left (make-branch 2 3)
61 | ; right (make-branch 2 4)
62 | ; mobile (make-mobile left right)]
63 | ; (is (not (balanced? mobile)))))
64 |
65 | ; d. Suppose we change the constructors to use 'cons' (scheme). How much do you need to change the programs
66 | ; to convert to the new representation?
67 |
68 | ; answer: only the selectors need to change, given a scheme-style cons. (car/cdr vs. car/cadr)
69 |
70 | (run-all-tests #"ex.*")
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_30.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_30
2 | (:use clojure.test))
3 |
4 | (defn square [x]
5 | (* x x))
6 |
7 | (defn square-tree-ugly [x]
8 | (cond (nil? x) nil
9 | (not (seq? x)) (square x)
10 | (empty? x) '()
11 | :default (cons (square-tree-ugly (first x))
12 | (square-tree-ugly (rest x)))))
13 |
14 | (defn square-tree-map [x]
15 | (map (fn [sub-x] (if (seq? sub-x)
16 | (square-tree-map sub-x)
17 | (square sub-x)))
18 | x))
19 |
20 | (deftest should-square-all-leaves-in-the-tree-the-ugly-way
21 | (let [expected '(1 (4 (9 16) 25) (36 49))
22 | input '(1 (2 (3 4) 5) (6 7))]
23 | (is (= expected (square-tree-ugly input)))))
24 |
25 | (deftest should-square-all-leaves-in-the-tree-with-map
26 | (let [expected '(1 (4 (9 16) 25) (36 49))
27 | input '(1 (2 (3 4) 5) (6 7))]
28 | (is (= expected (square-tree-map input)))))
29 |
30 | (run-all-tests #"ex.*")
31 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_31.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_31
2 | (:use clojure.test))
3 |
4 | (defn square [x]
5 | (* x x))
6 |
7 | (defn tree-map [f tree]
8 | (map (fn [sub-tree] (if (seq? sub-tree)
9 | (tree-map f sub-tree)
10 | (f sub-tree)))
11 | tree))
12 |
13 | (defn square-tree [tree]
14 | (tree-map square tree))
15 |
16 | (deftest should-square-all-leaves-in-the-tree
17 | (let [expected '(1 (4 (9 16) 25) (36 49))
18 | input '(1 (2 (3 4) 5) (6 7))]
19 | (is (= expected (square-tree input)))))
20 |
21 | (run-all-tests #"ex.*")
22 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_32.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_32
2 | (:use clojure.test))
3 |
4 | ; from 2.2.1
5 | (defn append [list1 list2]
6 | (if (empty? list1)
7 | list2
8 | (cons (first list1) (append (rest list1) list2))))
9 |
10 | (defn subsets [s]
11 | (if (empty? s)
12 | (list ())
13 | (let [remaining (subsets (rest s))
14 | with-head (map #(cons (first s) %) remaining)]
15 | (append remaining with-head))))
16 |
17 | (deftest should-find-all-subets-of-a-simple-set
18 | (let [expected [[] [2] [1] [1 2]]
19 | input [1 2]]
20 | (is (= expected (subsets input)))))
21 |
22 | (deftest should-find-all-possible-subsets-of-a-set
23 | (let [expected '(() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3))
24 | input '(1 2 3)]
25 | (is (= expected (subsets input)))))
26 |
27 | ; this was my attempt to solve 2.32 using Vectors. sadly, 'cons' poses similar problems for vectors as 'append' poses
28 | ; for lists. upon realizing this, I gave up on the effort because of the structure of the exercise.
29 | (defn subsets-vec [s]
30 | (if (empty? s)
31 | (vector [])
32 | (let [remaining (subsets-vec (rest s))
33 | with-head (map #(cons (first s) %) remaining)]
34 | (conj remaining with-head))))
35 |
36 | (run-all-tests #"ex.*")
37 |
--------------------------------------------------------------------------------
/src/sec2_2/ex2_33.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_33
2 | (:use clojure.test))
3 |
4 | ; need an accumulate like the book -- reduce won't work.
5 | (defn accumulate [op initial sq]
6 | (if (empty? sq)
7 | initial
8 | (op (first sq)
9 | (accumulate op initial (rest sq)))))
10 |
11 | (defn mymap [p seq]
12 | (accumulate (fn [x y] (cons (p x) y)) nil seq))
13 |
14 | (deftest should-perform-a-function-on-each-element-of-a-list
15 | (is (= '(2 4 6 8) (mymap #(* % 2) '(1 2 3 4)))))
16 |
17 | (defn myappend [seq1 seq2]
18 | (accumulate cons seq2 seq1))
19 |
20 | (deftest should-add-one-sequence-to-the-end-of-the-other
21 | (is (= '(1 2 3 4) (myappend '(1 2) '(3 4)))))
22 |
23 | (defn mylength [seq]
24 | (accumulate (fn [x y] (inc y)) 0 seq))
25 |
26 | (deftest should-count-the-items-in-a-sequence
27 | (is (= 5 (mylength '(:a :b :c :d :e)))))
28 |
29 | (run-tests)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_34.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_34
2 | (:use clojure.test))
3 |
4 | (defn accumulate [op initial sq]
5 | (if (empty? sq)
6 | initial
7 | (op (first sq)
8 | (accumulate op initial (rest sq)))))
9 |
10 | (defn horner-eval [x coefficent-sequence]
11 | (accumulate (fn [this-coeff higher-terms] (+ this-coeff (* x higher-terms)) )
12 | 0
13 | coefficent-sequence))
14 |
15 | (deftest test-horner-eval
16 | (is (= 79 (horner-eval 2 (list 1 3 0 5 0 1)))))
17 |
18 | (run-tests)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_35.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_36
2 | (:use clojure.test))
3 |
4 | (defn accumulate [op initial sq]
5 | (if (empty? sq)
6 | initial
7 | (op (first sq)
8 | (accumulate op initial (rest sq)))))
9 |
10 | (defn condense [x]
11 | (cond (not (seq? x)) 1
12 | (empty? x) 0
13 | :default (+ (condense (first x)) (condense (rest x)))))
14 |
15 | (defn count-leaves [t]
16 | (accumulate +
17 | 0
18 | (map condense t)))
19 |
20 | (deftest should-count-all-leaf-nodes
21 | (is (= 5 (count-leaves '((1 2) (3 4) 5)))))
22 |
23 | (run-tests)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_36.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_36
2 | (:use clojure.test))
3 |
4 | (defn accumulate [op initial sq]
5 | (if (empty? sq)
6 | initial
7 | (op (first sq)
8 | (accumulate op initial (rest sq)))))
9 |
10 | (defn accumulate-n [op init seqs]
11 | (if (empty? (first seqs))
12 | nil
13 | (cons (accumulate op init (map first seqs))
14 | (accumulate-n op init (map rest seqs)))))
15 |
16 | (deftest should-accumulate-across-multiple-seqs
17 | (let [s '((1 2 3) (4 5 6) (7 8 9) (10 11 12))]
18 | (is (= '(22 26 30) (accumulate-n + 0 s)))))
19 |
20 | (run-tests)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_37.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_37
2 | (:use clojure.test))
3 |
4 | (defn accumulate [op initial sq]
5 | (if (empty? sq)
6 | initial
7 | (op (first sq)
8 | (accumulate op initial (rest sq)))))
9 |
10 | (defn accumulate-n [op init seqs]
11 | (if (empty? (first seqs))
12 | nil
13 | (cons (accumulate op init (map first seqs))
14 | (accumulate-n op init (map rest seqs)))))
15 |
16 | (def matrix '((1 2 3 4) (4 5 6 6) (6 7 8 9)))
17 |
18 | (defn matrix-*-vector [m v]
19 | (map (fn [s a] (* a (accumulate + 0 s)))
20 | m
21 | v))
22 |
23 | (deftest should-multiply-a-matrix-and-vector-by-multiplying-each-row-of-the-matrix-with-the-vector-then-summing
24 | (let [v '(1 2 0)]
25 | (is (= '(10 42 0) (matrix-*-vector matrix v)))))
26 |
27 | (defn transpose [m]
28 | (accumulate-n cons nil m))
29 |
30 | (deftest test-transpose
31 | (is (= '((1 4 6) (2 5 7) (3 6 8) (4 6 9)) (transpose matrix))))
32 |
33 | (defn matrix-*-matrix [mat1 mat2]
34 | (let [cols (transpose mat2)]
35 | (map (fn [row]
36 | (map (fn [column] (accumulate + 0 (map * row column)))
37 | cols))
38 | mat1)))
39 |
40 | (def expected '((30 56 80) (56 113 161) (80 161 230)))
41 | (deftest test-matrix-*-matrix
42 | (is (= expected
43 | (matrix-*-matrix matrix (transpose matrix)))))
44 |
45 |
46 | (run-tests)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_38.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_38
2 | (:use clojure.test))
3 |
4 | (defn fold-right [op initial sq]
5 | (if (empty? sq)
6 | initial
7 | (op (first sq)
8 | (fold-right op initial (rest sq)))))
9 |
10 | (defn fold-left [op initial sq]
11 | (loop [result initial
12 | remaining sq]
13 | (if (empty? remaining)
14 | result
15 | (recur (op result (first remaining)) (rest remaining)))))
16 |
17 | (println (fold-right / 1 (list 1 2 3)))
18 | (println (fold-left / 1 (list 1 2 3)))
19 | (println (fold-right list nil (list 1 2 3)))
20 | (println (fold-left list nil (list 1 2 3)))
21 |
22 | (run-tests)
--------------------------------------------------------------------------------
/src/sec2_2/ex2_39.clj:
--------------------------------------------------------------------------------
1 | (ns sec2_2.ex2_39
2 | (:use clojure.test))
3 |
4 | (defn fold-right [op initial sq]
5 | (if (empty? sq)
6 | initial
7 | (op (first sq)
8 | (fold-right op initial (rest sq)))))
9 |
10 | (defn fold-left [op initial sq]
11 | (loop [result initial
12 | remaining sq]
13 | (if (empty? remaining)
14 | result
15 | (recur (op result (first remaining)) (rest remaining)))))
16 |
17 | ; from 2.2.1
18 | (defn append [list1 list2]
19 | (if (empty? list1)
20 | list2
21 | (cons (first list1) (append (rest list1) list2))))
22 |
23 | ; feels backwards because fold-right actually works inside-out, starting with 3.
24 | (defn reverse-right [s]
25 | (fold-right (fn [x acc] (append acc (list x))) nil s))
26 |
27 | (deftest should-reverse-a-list-using-fold-right
28 | (is (= '(3 2 1) (reverse-right '(1 2 3)))))
29 |
30 | ; maybe these should be called 'fold-from-left' and 'fold-from-right'?
31 | (defn reverse-left [s]
32 | (fold-left (fn [acc x] (println x) (cons x acc)) '() s))
33 |
34 | (deftest should-reverse-a-list-using-fold-left
35 | (is (= '(3 2 1) (reverse-left '(1 2 3)))))
36 |
37 | (run-tests)
--------------------------------------------------------------------------------
/test/ch4/environment_test.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.environment-test
3 | (:use clojure.test
4 | ch4.environment))
5 |
6 | (deftest can-create-frame
7 | (let [f (make-frame '(a b c d) '(1 2 3 4))]
8 | (is (= '(a b c d) (sort (frame-variables f))))
9 | (is (= '(1 2 3 4) (sort (frame-values f))))))
10 |
11 | (deftest can-add-vars-to-frame
12 | (let [f (make-frame '() '())]
13 | (add-binding-to-frame! 'a 1 f)
14 | (is (= '(a) (frame-variables f)))
15 | (is (= '(1) (frame-values f)))))
16 |
17 | (deftest can-lookup-variable-in-environment
18 | (let [e (extend-environment '(a b c d)
19 | '(1 2 3 4)
20 | the-empty-environment)]
21 | (is (= 1 (lookup-variable-value 'a e)))))
22 |
23 | (deftest can-set-variable-in-environment
24 | (let [e (extend-environment '(a b c d)
25 | '(1 2 3 4)
26 | the-empty-environment)]
27 | (set-variable-value! 'a 10 e)
28 | (is (= 10 (lookup-variable-value 'a e)))))
29 |
30 | (deftest can-define-new-variable
31 | (let [e (extend-environment '(a b c d)
32 | '(1 2 3 4)
33 | the-empty-environment)]
34 | (define-variable! 'e 5 e)
35 | (is (= 5 (lookup-variable-value 'e e)))))
36 |
37 | (deftest can-define-variable-which-already-exists
38 | (let [e (extend-environment '(a b c d)
39 | '(1 2 3 4)
40 | the-empty-environment)]
41 | (define-variable! 'b 11 e)
42 | (is (= 11 (lookup-variable-value 'b e)))))
43 |
44 | (deftest can-lookup-variables-which-have-false-value
45 | (let [e (extend-environment '(a b c d)
46 | '(1 2 3 4)
47 | the-empty-environment)]
48 | (define-variable! 'g false e)
49 | (define-variable! 'f nil e)
50 | (is (= false (lookup-variable-value 'g e)))
51 | (is (= nil (lookup-variable-value 'f e)))))
52 |
53 | (deftest need-to-make-copy-of-environment
54 | (let [e (extend-environment '(a)
55 | '(1)
56 | the-empty-environment)
57 | e2 (copy-environment e)]
58 | (is (environments-equal? e e2))
59 | (define-variable! 'b 2 e2)
60 | (is (not (environments-equal? e e2)))))
61 |
62 | (deftest can-unbind-variable-from-frame
63 | (let [e (extend-environment '(a b c d)
64 | '(1 2 3 4)
65 | the-empty-environment)]
66 | (is (= 1 (lookup-variable-value 'a e)))
67 | (unbind-variable! 'a e)
68 | (is (= (type (Error.)) (type (lookup-variable-value 'a e))))))
69 |
70 | ; Exercise 4.16(a)
71 | (deftest unassigned-variable-gets-error
72 | (let [e (extend-environment '(a)
73 | '(1)
74 | the-empty-environment)]
75 | (set-variable-value! 'e '*unassigned* e)
76 | (is (= (type (Error.)) (type (lookup-variable-value 'e e))))))
77 |
--------------------------------------------------------------------------------
/test/ch4/scheme_test.clj:
--------------------------------------------------------------------------------
1 |
2 | (ns ch4.scheme-test
3 | (:use clojure.test
4 | ch4.scheme))
5 |
6 | (use-fixtures :each (fn [f] (reset-global-environment) (f)))
7 |
8 | (deftest test-self-eval
9 | (is (= 5 (interpret 5)))
10 | (is (= "hey" (interpret "hey"))))
11 |
12 | (deftest test-expressions
13 | (are [x y] (= x y)
14 | 3 (interpret '(+ 1 2))
15 | -14 (interpret '(* (- 10 3) (- 4 6)))
16 | 8 (interpret '(* (/ 4 2) (- 6 4) (+ 1 1)))))
17 |
18 | (deftest test-quoted
19 | (are [x y] (= x y)
20 | 2 (interpret '(quote 2))
21 | 'howdy (interpret '(quote howdy))
22 | '(jake jim 2) (interpret '(quote (jake jim 2)))))
23 |
24 | (deftest test-if
25 | (are [x] (true? (interpret x))
26 | '(if (= 1 1) true false)
27 | '(if (= 1 0) false true)
28 | '(if 1 true false)
29 | ; '(if nil false true)
30 | ))
31 |
32 | (deftest test-cond
33 | (are [x] (true? (interpret x))
34 | '(cond ((= 1 2) false)
35 | ((= 2 2) true)
36 | ((= 2 3) false))
37 | '(cond ((= 1 2) false)
38 | ((= 2 3) false)
39 | (else true))))
40 |
41 | ; For exercise 4.5
42 | (deftest test-different-cond-format
43 | (is (= 2 (interpret '(cond ((1 2 3) => cadr)
44 | (else false))))))
45 |
46 | (deftest test-or
47 | (is (interpret '(or 5 4 3)))
48 | (is (false? (interpret '(or false false)))))
49 |
50 | (deftest test-and
51 | (is (true? (interpret '(and true true))))
52 | (is (false? (interpret '(and false true)))))
53 |
54 | (deftest test-vars
55 | (interpret '(define twelve 12))
56 | (is (= 12 (interpret 'twelve)))
57 | (is (= 14 (interpret '(+ twelve 2))))
58 | (interpret '(define two 2))
59 | (is (= 2 (interpret 'two)))
60 | (is (= 14 (interpret '(+ two twelve))))
61 | (interpret '(set! twelve 9))
62 | (is (= 9 (interpret 'twelve))))
63 |
64 | (deftest test-define
65 | (interpret
66 | '(define (ident a) a))
67 | (interpret '(define (sum a b) (+ a b)))
68 | (is (= 5 (interpret '(ident 5))))
69 | (is (= 10 (interpret '(sum 4 6))))
70 | (is (= 11 (interpret '(sum (ident 5) 6)))))
71 |
72 | (deftest test-lambdas
73 | (is (= 10 (interpret '((lambda (a b) (+ a b)) 7 3)))))
74 |
75 | (deftest test-recursive-function
76 | (interpret
77 | '(define (exp x y)
78 | (if (= y 1)
79 | x
80 | (exp (* x x) (- y 1)))))
81 | (is (= 25 (interpret '(exp 5 2)))))
82 |
83 | ; Exercise 4.6
84 | (deftest basic-let-form-works
85 | (is (= 2
86 | (interpret '(let ((a 2))
87 | a))))
88 | (is (= 42
89 | (interpret '(let ((a 2) (b 40))
90 | (+ a b))))))
91 |
92 | ; Exercise 4.7
93 | (deftest let*-works
94 | (is (= 42
95 | (interpret '(let* ((a 2)
96 | (b (+ a 40)))
97 | b))))
98 | (is (= 39
99 | (interpret '(let* ((x 3)
100 | (y (+ x 2))
101 | (z (+ x y 5)))
102 | (* x z))))))
103 |
104 | ; Exercise 4.8
105 | (deftest let-supports-named-let
106 | (interpret '(define (fib n)
107 | (let fib-iter ((a 1)
108 | (b 0)
109 | (count n))
110 | (if (= count 0)
111 | b
112 | (fib-iter (+ a b) a (- count 1))))))
113 | (is (= 3 (interpret '(fib 4)))))
114 |
115 | ; Exercise 4.13
116 | (deftest can-remove-binding-from-environment
117 | (interpret '(define a 1))
118 | (is (= 1 (interpret 'a)))
119 | (interpret '(make-unbound! a))
120 | (is (= (type (Error.)) (type (interpret 'a)))))
121 |
122 | ; Exercise 4.16
123 | (deftest scans-out-internal-definitions
124 | (is (=
125 | '(lambda jake
126 | (let ((u '*unassigned*)
127 | (v '*unassigned*))
128 | (set! u e1)
129 | (set! v e2)
130 | e3))
131 |
132 | (scan-out-defines
133 | '(lambda jake
134 | (define u e1)
135 | (define v e2)
136 | e3)))))
137 |
138 | (deftest scan-out-defines-returns-original-when-no-internal-defines
139 | (let [statement '(lambda (a b c d)
140 | (+ a (- b (+ c d))))]
141 | (is (= statement
142 | (scan-out-defines statement)))))
143 |
144 | ; Exercise 4.20
145 | (deftest letrec-works-by-transforming-into-let-set!-combo
146 | (is (= '(let ((increment '*unassigned*))
147 | (begin
148 | (set! increment (lambda (n)
149 | (+ 1 n)))
150 | (increment 1)))
151 |
152 | (letrec->let '(letrec ((increment
153 | (lambda (n)
154 | (+ 1 n))))
155 | (increment 1))))))
156 |
157 | (deftest letrec-can-be-evalulated
158 | (is (= 2
159 | (interpret '(letrec ((increment
160 | (lambda (n)
161 | (+ 1 n))))
162 | (increment 1))))))
163 |
--------------------------------------------------------------------------------
/tools/repl.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | java -cp .:lib/jline-0.9.94.jar:lib/clojure-1.1.0-alpha-SNAPSHOT.jar:lib/clojure-contrib.jar jline.ConsoleRunner clojure.lang.Repl
4 |
5 |
--------------------------------------------------------------------------------