├── 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 | --------------------------------------------------------------------------------