Ver código fonte

first commit.

"Programs must be written for people to read, and only incidentally for machines to execute."
-- Abelson & Sussman, SCIP, preface to the first edition
Stanley Bileschi 12 anos atrás
commit
d65b774d57

+ 4 - 0
.gitignore

1
+# ignore some editor temp files
2
+*~
3
+.#*
4
+.*.sw?

+ 177 - 0
LICENSE

1
+
2
+                                 Apache License
3
+                           Version 2.0, January 2004
4
+                        http://www.apache.org/licenses/
5
+
6
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+   1. Definitions.
9
+
10
+      "License" shall mean the terms and conditions for use, reproduction,
11
+      and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+      "Licensor" shall mean the copyright owner or entity authorized by
14
+      the copyright owner that is granting the License.
15
+
16
+      "Legal Entity" shall mean the union of the acting entity and all
17
+      other entities that control, are controlled by, or are under common
18
+      control with that entity. For the purposes of this definition,
19
+      "control" means (i) the power, direct or indirect, to cause the
20
+      direction or management of such entity, whether by contract or
21
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+      outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+      "You" (or "Your") shall mean an individual or Legal Entity
25
+      exercising permissions granted by this License.
26
+
27
+      "Source" form shall mean the preferred form for making modifications,
28
+      including but not limited to software source code, documentation
29
+      source, and configuration files.
30
+
31
+      "Object" form shall mean any form resulting from mechanical
32
+      transformation or translation of a Source form, including but
33
+      not limited to compiled object code, generated documentation,
34
+      and conversions to other media types.
35
+
36
+      "Work" shall mean the work of authorship, whether in Source or
37
+      Object form, made available under the License, as indicated by a
38
+      copyright notice that is included in or attached to the work
39
+      (an example is provided in the Appendix below).
40
+
41
+      "Derivative Works" shall mean any work, whether in Source or Object
42
+      form, that is based on (or derived from) the Work and for which the
43
+      editorial revisions, annotations, elaborations, or other modifications
44
+      represent, as a whole, an original work of authorship. For the purposes
45
+      of this License, Derivative Works shall not include works that remain
46
+      separable from, or merely link (or bind by name) to the interfaces of,
47
+      the Work and Derivative Works thereof.
48
+
49
+      "Contribution" shall mean any work of authorship, including
50
+      the original version of the Work and any modifications or additions
51
+      to that Work or Derivative Works thereof, that is intentionally
52
+      submitted to Licensor for inclusion in the Work by the copyright owner
53
+      or by an individual or Legal Entity authorized to submit on behalf of
54
+      the copyright owner. For the purposes of this definition, "submitted"
55
+      means any form of electronic, verbal, or written communication sent
56
+      to the Licensor or its representatives, including but not limited to
57
+      communication on electronic mailing lists, source code control systems,
58
+      and issue tracking systems that are managed by, or on behalf of, the
59
+      Licensor for the purpose of discussing and improving the Work, but
60
+      excluding communication that is conspicuously marked or otherwise
61
+      designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+      "Contributor" shall mean Licensor and any individual or Legal Entity
64
+      on behalf of whom a Contribution has been received by Licensor and
65
+      subsequently incorporated within the Work.
66
+
67
+   2. Grant of Copyright License. Subject to the terms and conditions of
68
+      this License, each Contributor hereby grants to You a perpetual,
69
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+      copyright license to reproduce, prepare Derivative Works of,
71
+      publicly display, publicly perform, sublicense, and distribute the
72
+      Work and such Derivative Works in Source or Object form.
73
+
74
+   3. Grant of Patent License. Subject to the terms and conditions of
75
+      this License, each Contributor hereby grants to You a perpetual,
76
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+      (except as stated in this section) patent license to make, have made,
78
+      use, offer to sell, sell, import, and otherwise transfer the Work,
79
+      where such license applies only to those patent claims licensable
80
+      by such Contributor that are necessarily infringed by their
81
+      Contribution(s) alone or by combination of their Contribution(s)
82
+      with the Work to which such Contribution(s) was submitted. If You
83
+      institute patent litigation against any entity (including a
84
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+      or a Contribution incorporated within the Work constitutes direct
86
+      or contributory patent infringement, then any patent licenses
87
+      granted to You under this License for that Work shall terminate
88
+      as of the date such litigation is filed.
89
+
90
+   4. Redistribution. You may reproduce and distribute copies of the
91
+      Work or Derivative Works thereof in any medium, with or without
92
+      modifications, and in Source or Object form, provided that You
93
+      meet the following conditions:
94
+
95
+      (a) You must give any other recipients of the Work or
96
+          Derivative Works a copy of this License; and
97
+
98
+      (b) You must cause any modified files to carry prominent notices
99
+          stating that You changed the files; and
100
+
101
+      (c) You must retain, in the Source form of any Derivative Works
102
+          that You distribute, all copyright, patent, trademark, and
103
+          attribution notices from the Source form of the Work,
104
+          excluding those notices that do not pertain to any part of
105
+          the Derivative Works; and
106
+
107
+      (d) If the Work includes a "NOTICE" text file as part of its
108
+          distribution, then any Derivative Works that You distribute must
109
+          include a readable copy of the attribution notices contained
110
+          within such NOTICE file, excluding those notices that do not
111
+          pertain to any part of the Derivative Works, in at least one
112
+          of the following places: within a NOTICE text file distributed
113
+          as part of the Derivative Works; within the Source form or
114
+          documentation, if provided along with the Derivative Works; or,
115
+          within a display generated by the Derivative Works, if and
116
+          wherever such third-party notices normally appear. The contents
117
+          of the NOTICE file are for informational purposes only and
118
+          do not modify the License. You may add Your own attribution
119
+          notices within Derivative Works that You distribute, alongside
120
+          or as an addendum to the NOTICE text from the Work, provided
121
+          that such additional attribution notices cannot be construed
122
+          as modifying the License.
123
+
124
+      You may add Your own copyright statement to Your modifications and
125
+      may provide additional or different license terms and conditions
126
+      for use, reproduction, or distribution of Your modifications, or
127
+      for any such Derivative Works as a whole, provided Your use,
128
+      reproduction, and distribution of the Work otherwise complies with
129
+      the conditions stated in this License.
130
+
131
+   5. Submission of Contributions. Unless You explicitly state otherwise,
132
+      any Contribution intentionally submitted for inclusion in the Work
133
+      by You to the Licensor shall be under the terms and conditions of
134
+      this License, without any additional terms or conditions.
135
+      Notwithstanding the above, nothing herein shall supersede or modify
136
+      the terms of any separate license agreement you may have executed
137
+      with Licensor regarding such Contributions.
138
+
139
+   6. Trademarks. This License does not grant permission to use the trade
140
+      names, trademarks, service marks, or product names of the Licensor,
141
+      except as required for reasonable and customary use in describing the
142
+      origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+   7. Disclaimer of Warranty. Unless required by applicable law or
145
+      agreed to in writing, Licensor provides the Work (and each
146
+      Contributor provides its Contributions) on an "AS IS" BASIS,
147
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+      implied, including, without limitation, any warranties or conditions
149
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+      PARTICULAR PURPOSE. You are solely responsible for determining the
151
+      appropriateness of using or redistributing the Work and assume any
152
+      risks associated with Your exercise of permissions under this License.
153
+
154
+   8. Limitation of Liability. In no event and under no legal theory,
155
+      whether in tort (including negligence), contract, or otherwise,
156
+      unless required by applicable law (such as deliberate and grossly
157
+      negligent acts) or agreed to in writing, shall any Contributor be
158
+      liable to You for damages, including any direct, indirect, special,
159
+      incidental, or consequential damages of any character arising as a
160
+      result of this License or out of the use or inability to use the
161
+      Work (including but not limited to damages for loss of goodwill,
162
+      work stoppage, computer failure or malfunction, or any and all
163
+      other commercial damages or losses), even if such Contributor
164
+      has been advised of the possibility of such damages.
165
+
166
+   9. Accepting Warranty or Additional Liability. While redistributing
167
+      the Work or Derivative Works thereof, You may choose to offer,
168
+      and charge a fee for, acceptance of support, warranty, indemnity,
169
+      or other liability obligations and/or rights consistent with this
170
+      License. However, in accepting such obligations, You may act only
171
+      on Your own behalf and on Your sole responsibility, not on behalf
172
+      of any other Contributor, and only if You agree to indemnify,
173
+      defend, and hold each Contributor harmless for any liability
174
+      incurred by, or claims asserted against, such Contributor by reason
175
+      of your accepting any such warranty or additional liability.
176
+
177
+   END OF TERMS AND CONDITIONS

+ 61 - 0
README

1
+Getting Started
2
+---------------
3
+
4
+From a terminal, execute your lisp interpreter on the file 'contemplate.lsp' e.g.
5
+
6
+    sbcl --script contemplate.lsp
7
+
8
+Running on a fresh version should output the following:
9
+
10
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
11
+Thinking about ASSERTS
12
+    ASSERT-TRUE has damaged your karma.
13
+
14
+You have not yet reached enlightenment ...
15
+  A koan is incomplete.
16
+
17
+Please meditate on the following code:
18
+   File "koans/asserts.lsp"
19
+   Koan "ASSERT-TRUE"
20
+   Current koan assert status is "(INCOMPLETE)"
21
+
22
+You are now 0/169 koans and 0/25 lessons away from reaching enlightenment
23
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
24
+
25
+
26
+This indicates that the script has completed, and that the learner should look
27
+to asserts.lsp to locate and fix the problem.  The problem will be within 
28
+a define-test block such as
29
+
30
+    (define-test assert-true
31
+        "t is true.  Replace the blank with a t"
32
+        (assert-true ___))
33
+
34
+In this case, the test is incomplete, and the student should fill 
35
+in the blank (____) with appropriate lisp code to make the assert pass.
36
+
37
+
38
+In order to test code, or evaluate tests interactively, students may copy
39
+and paste code into the lisp command line REPL.
40
+
41
+
42
+Quoting the Ruby Koans instructions::
43
+-------------------------------------
44
+
45
+   "In test-driven development the mantra has always been, red, green, 
46
+refactor. Write a failing test and run it (red), make the test pass (green),
47
+then refactor it (that is look at the code and see if you can make it any
48
+better. In this case you will need to run the koan and see it fail (red), make
49
+the test pass (green), then take a moment and reflect upon the test to see what
50
+it is teaching you and improve the code to better communicate its
51
+intent (refactor)."
52
+
53
+
54
+Content
55
+-------
56
+
57
+The Common Lisp koans are based on the python koans and ruby koans projects.
58
+Additionally, many of the tests are based on new material that is special
59
+to Common Lisp.
60
+
61
+Note that the unit on threads uses an SBCL specific threading API.

+ 6 - 0
TODO

1
+*  replace koans/threads.lsp with a more general thread library
2
+*  make get-error-filename more maintainable
3
+*  make get-error-koan-name more maintainable
4
+*  make get-error-koan-status more maintainable
5
+
6
+

+ 202 - 0
contemplate.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+(in-package :cl-user)
17
+
18
+;; lisp-unit defines the modules for loading / executing koans
19
+(load "lisp-unit.lsp")
20
+
21
+(defpackage :lisp-koans
22
+  (:use :common-lisp)
23
+  (:use :lisp-unit)
24
+  (:use :sb-ext))
25
+
26
+(in-package :lisp-koans)
27
+
28
+;; .koans file controls which files in *koan-dir-name* are loaded as
29
+;; koans to complete
30
+(defvar *koan-dir-name* "koans")
31
+(with-open-file (in #P".koans")
32
+  (with-standard-io-syntax
33
+    (defvar *all-koans-groups* (read in))))
34
+
35
+;; set *print-koan-progress* to t to list all completed koans before summary
36
+(defvar *print-koan-progress* t)
37
+;; debug-print directives
38
+(defvar *dp-loading* nil)
39
+
40
+
41
+;; Global state used to hold results of loading and processing koans
42
+(defvar *n-total-koans* 0)
43
+(defvar *collected-results* nil)
44
+
45
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46
+;; Functions for loading koans ;;
47
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48
+
49
+(defun load-koan-group-named (koan-group-name)
50
+  ;; Creates a package for the koan-group based on koan-group-name.
51
+  ;; Loads a lisp file at *koan-dir-name* / koan-group-name .lsp
52
+  ;; Adds all the koans from that file to the package.
53
+  (let ((koan-file-name (concatenate 'string (string-downcase (string koan-group-name)) ".lsp")))
54
+    (if *dp-loading* (format t "start loading ~A ~%" koan-file-name))
55
+    (in-package :lisp-koans)
56
+    (make-package koan-group-name
57
+        :use '(:common-lisp :lisp-unit :sb-ext))
58
+    (setf *package* (find-package koan-group-name))
59
+    (load (concatenate 'string *koan-dir-name* "/" koan-file-name))
60
+    (incf *n-total-koans* (length (list-tests)))
61
+    (in-package :lisp-koans)
62
+    (if *dp-loading* (format t "done loading ~A ~%" koan-file-name))))
63
+
64
+
65
+
66
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
67
+;; Functions for executing koans ;;
68
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
69
+
70
+(defun run-koan-group-named (koan-group-name)
71
+  ;; Executes the koan group, using run-koans defined in lisp-unit
72
+  ;; returning a test-results object.
73
+  (if *dp-loading* (format t "start running ~A ~%" koan-group-name))
74
+  (run-koans koan-group-name))
75
+
76
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
77
+;; Functions for printing progress ;;
78
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79
+
80
+(defun print-one-koan-status (k-result)
81
+  (let ((koan-name (first k-result))
82
+        (all-pass-p (every
83
+                     #'(lambda (x) (equalp :pass x))
84
+                     (second k-result))))
85
+    (if all-pass-p
86
+        (format t "~A has expanded your awareness.~%" koan-name)
87
+        (format t "~A has damaged your karma.~%" koan-name))))
88
+
89
+(defun print-koan-group-progress (kg-name kg-results)
90
+  (format t "~%Thinking about ~A~%" kg-name)
91
+  (dolist (k-result (reverse kg-results))
92
+    (format t "    ")
93
+    (print-one-koan-status k-result))
94
+  (format t "~%"))
95
+
96
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
97
+;; Functions for processing results ;;
98
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
99
+
100
+(defun any-assert-non-pass-p ()
101
+   (dolist (k-group-result *collected-results*)
102
+     (dolist (koan-result (second k-group-result))
103
+       (dolist (one-assert (second koan-result))
104
+         (if (not (equal one-assert :pass))
105
+             (return-from any-assert-non-pass-p one-assert)))))
106
+   nil)
107
+
108
+(defun get-error-filename (collected-results)
109
+  (first (first (last collected-results))))
110
+
111
+(defun get-error-koan-name (collected-results)
112
+  (first (first (second (first (last (last collected-results)))))))
113
+
114
+(defun get-error-koan-status (collected-results)
115
+  (second (first (second (first (last (last collected-results)))))))
116
+
117
+(defun koan-status-message (koan-status)
118
+  (if (find :incomplete koan-status)
119
+       (return-from koan-status-message
120
+         "  A koan is incomplete.~%"))
121
+  (if (find :fail koan-status)
122
+       (return-from koan-status-message
123
+         "  A koan is incorrect.~%"))
124
+  (if (find :error koan-status)
125
+       (return-from koan-status-message
126
+         "  A koan threw an error.~%"))
127
+  (format t "  last koan status: ~A~%" koan-status)
128
+  "")
129
+
130
+(defun print-next-suggestion-message ()
131
+  (let ((filename (get-error-filename *collected-results*))
132
+        (koan-name (get-error-koan-name *collected-results*))
133
+        (koan-status (get-error-koan-status *collected-results*)))
134
+    (format t "You have not yet reached enlightenment ...~%")
135
+    (format t (koan-status-message koan-status))
136
+    (format t "~%")
137
+    (format t "Please meditate on the following code:~%")
138
+    (format t "   File \"~A/~A.lsp\"~%" *koan-dir-name* (string-downcase filename))
139
+    (format t "   Koan \"~A\"~%" koan-name)
140
+    (format t "   Current koan assert status is \"~A\"~%" (reverse koan-status))))
141
+
142
+(defun print-completion-message ()
143
+  (format t "That was the last one, well done!~%")
144
+  (format t "If you want more, take a look at extra-credit.lsp~%"))
145
+
146
+(defun n-completed-koans (collected-results)
147
+  (loop for kg in collected-results
148
+        sum (length (second kg)) into partial-sum
149
+        finally (return partial-sum)))
150
+
151
+(defun all-asserts-passed-in-koan-p (koan-result)
152
+  (equal
153
+   (length (second koan-result))
154
+   (count :pass (second koan-result))))
155
+
156
+(defun n-passed-koans-in-group (kg)
157
+  (loop for k in (second kg)
158
+        counting (all-asserts-passed-in-koan-p k) into partial-sum
159
+        finally (return partial-sum)))
160
+
161
+(defun n-passed-koans-overall (collected-results)
162
+  (loop for kg in collected-results
163
+        sum (n-passed-koans-in-group kg) into partial-sum
164
+        finally (return partial-sum)))
165
+
166
+(defun print-progress-message ()
167
+      (format t "You are now ~A/~A koans and ~A/~A lessons away from reaching enlightenment~%~%"
168
+              (n-passed-koans-overall *collected-results*)
169
+              *n-total-koans*
170
+              (- (length *collected-results*) 1)
171
+              (length *all-koans-groups*)))
172
+
173
+
174
+;;;;;;;;;;
175
+;; Main ;;
176
+;;;;;;;;;;
177
+
178
+;; Load all the koans before testing any, and
179
+;; count how many total koans there are.
180
+(loop for koan-group-name in *all-koans-groups*
181
+      do
182
+   (load-koan-group-named koan-group-name))
183
+
184
+;; Run through the koans until reaching the end condition.
185
+;; Store the results in *collected-results*
186
+(setf *collected-results*
187
+      (loop for koan-group-name in *all-koans-groups*
188
+            for kg-results = (run-koan-group-named koan-group-name)
189
+            collect (list koan-group-name kg-results)
190
+            do (if *print-koan-progress*
191
+                   (print-koan-group-progress koan-group-name kg-results))
192
+               ;; *proceed-after-failure* is defined in lisp-unit
193
+            until (and (not *proceed-after-failure*) (any-non-pass-p kg-results))))
194
+
195
+
196
+;; Output advice to the learner
197
+(if (any-assert-non-pass-p)
198
+    (progn
199
+      (print-next-suggestion-message)
200
+      (format t "~%")
201
+      (print-progress-message))
202
+    (print-completion-message))

+ 66 - 0
koans/GREED_RULES.txt

1
+= Playing Greed
2
+
3
+Greed is a dice game played among 2 or more players, using 5
4
+six-sided dice.
5
+
6
+== Playing Greed
7
+
8
+Each player takes a turn consisting of one or more rolls of the dice.
9
+On the first roll of the game, a player rolls all five dice which are
10
+scored according to the following:
11
+
12
+  Three 1's => 1000 points
13
+  Three 6's =>  600 points
14
+  Three 5's =>  500 points
15
+  Three 4's =>  400 points
16
+  Three 3's =>  300 points
17
+  Three 2's =>  200 points
18
+  One   1   =>  100 points
19
+  One   5   =>   50 points
20
+
21
+A single die can only be counted once in each roll.  For example,
22
+a "5" can only count as part of a triplet (contributing to the 500
23
+points) or as a single 50 points, but not both in the same roll.
24
+
25
+Example Scoring
26
+
27
+   Throw       Score
28
+   ---------   ------------------
29
+   5 1 3 4 1   50 + 2 * 100 = 250
30
+   1 1 1 3 1   1000 + 100 = 1100
31
+   2 4 4 5 4   400 + 50 = 450
32
+
33
+The dice not contributing to the score are called the non-scoring
34
+dice.  "3" and "4" are non-scoring dice in the first example.  "3" is
35
+a non-scoring die in the second, and "2" is a non-score die in the
36
+final example.
37
+
38
+After a player rolls and the score is calculated, the scoring dice are
39
+removed and the player has the option of rolling again using only the
40
+non-scoring dice. If all of the thrown dice are scoring, then the
41
+player may roll all 5 dice in the next roll.
42
+
43
+The player may continue to roll as long as each roll scores points. If
44
+a roll has zero points, then the player loses not only their turn, but
45
+also accumulated score for that turn. If a player decides to stop
46
+rolling before rolling a zero-point roll, then the accumulated points
47
+for the turn is added to his total score.
48
+
49
+== Getting "In The Game"
50
+
51
+Before a player is allowed to accumulate points, they must get at
52
+least 300 points in a single turn. Once they have achieved 300 points
53
+in a single turn, the points earned in that turn and each following
54
+turn will be counted toward their total score.
55
+
56
+== End Game
57
+
58
+Once a player reaches 3000 (or more) points, the game enters the final
59
+round where each of the other players gets one more turn. The winner
60
+is the player with the highest score after the final round.
61
+
62
+== References
63
+
64
+Greed is described on Wikipedia at
65
+http://en.wikipedia.org/wiki/Greed_(dice_game), however the rules are
66
+a bit different from the rules given here.

+ 79 - 0
koans/arrays.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; see http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node157.html
17
+
18
+
19
+(define-test test-basic-array-stuff
20
+    " the first block of code defines an 8x8 array, then fills
21
+      the elements with a checkerboard pattern"
22
+  (let ((chess-board))
23
+    (setf chess-board (make-array '(8 8)))
24
+    "this dotimes is an iterator which loops x over integers 0 to 7"
25
+    (dotimes (x 8)
26
+      (dotimes (y 8)
27
+        (if (evenp (+ x y))
28
+            (setf (aref chess-board x y) :black)
29
+            (setf (aref chess-board x y) :white)
30
+            )))
31
+    (assert-true (typep chess-board 'array))
32
+    (assert-equal (aref chess-board 0 0) ___)
33
+    (assert-equal (aref chess-board 2 3) ___)
34
+    "array-rank returns the number of dimensions of the array"
35
+    (assert-equal ___ (array-rank chess-board))
36
+    "array-dimensions returns a list of the cardinality of the array dims"
37
+    (assert-equal ___ (array-dimensions chess-board))
38
+    (assert-equal ___ (array-total-size chess-board))))
39
+
40
+(define-test test-make-your-own-array
41
+    "make your own array that meets the specifications below."
42
+  (let ((color-cube nil))
43
+    "you may need to modify your array after you make it"
44
+    (if (typep color-cube '(simple-array T (3 3 3)))
45
+        (progn
46
+          (assert-equal 3 (array-rank color-cube))
47
+          (assert-equal '(3 3 3) (array-dimensions color-cube))
48
+          (assert-equal 27 (array-total-size color-cube))
49
+          (assert-equal (aref color-cube 0 1 2) :red)
50
+          (assert-equal (aref color-cube 2 1 0) :white))
51
+        (assert-true nil))))
52
+
53
+
54
+(define-test test-adjustable-array
55
+    "one may build arrays that can change size"
56
+  (let ((x (make-array '(2 2) :initial-element 5 :adjustable t)))
57
+    (assert-equal (aref x 1 0) 5)
58
+    (assert-equal (array-dimensions x) '(2 2))
59
+    (adjust-array x '(3 4))
60
+    (assert-equal (array-dimensions x) '(3 4))
61
+    (assert-equal (aref x 2 3) ____)))
62
+
63
+
64
+(define-test test-make-array-from-list
65
+  (let ((x))
66
+    (setf x (make-array '(4) :initial-contents '(:one :two :three :four)))
67
+    (assert-equal (array-dimensions x) ____)
68
+    (assert-equal ____ (aref x 0))))
69
+
70
+
71
+(define-test test-row-major-index
72
+    "row major indexing is a way to access elements with a single integer,
73
+     rather than a list of integers"
74
+  (let ((my-array nil))
75
+    (setf my-array (make-array '(2 2 2 2)))
76
+    (dotimes (i (* 2 2 2 2))
77
+      (setf (row-major-aref my-array i) i))
78
+    (assert-equal (aref my-array 0 0 0 0) ____)
79
+    (assert-equal (aref my-array 1 1 1 1) ____)))

+ 47 - 0
koans/asserts.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+; Concept: What do you do to go through the lisp koans?  You fill in
17
+; the blanks, or otherwise fix the lisp code so that the
18
+; code within the 'define-koan' blocks passes.
19
+
20
+
21
+; In common lisp, "True" and "False" are represented by "t" and "nil".
22
+; More in a future lesson, but for now, consider t to be true,
23
+; and nil to be false.
24
+
25
+
26
+(define-test assert-true
27
+    "t is true.  Replace the blank with a t"
28
+    (assert-true ___))
29
+
30
+(define-test assert-false
31
+    "nil is false"
32
+    (assert-false ___))
33
+
34
+(define-test fill-in-the-blank
35
+    "sometimes you will need to fill the blank to complete"
36
+    (assert-equal 2 ___))
37
+
38
+(define-test fill-in-the-blank-string
39
+    (assert-equal ___ "hello world"))
40
+
41
+(define-test test-true-or-false
42
+    "sometimes you will be asked to evaluate whether statements 
43
+     are true (t) or false (nil)"
44
+    (true-or-false? ___ (equal 34 34))
45
+    (true-or-false? ___ (equal 19 78)))
46
+
47
+

+ 48 - 0
koans/atoms-vs-lists.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+(define-test test-list-or-atom
17
+    "Lists in lisp are forms beginning and ending with rounded parentheses.
18
+     Atoms are symbols, numbers, or other forms usually separated by
19
+     white-space or parentheses.  The function 'listp' will return true iff
20
+     the input is a list.  The function 'atom' will return true iff the
21
+     input is an atom."
22
+  (true-or-false? ___ (listp '(1 2 3)))
23
+  (true-or-false? ___ (atom '(1 2 3)))
24
+
25
+  (true-or-false? ___ (listp '("heres" "some" "strings")))
26
+  (true-or-false? ___ (atom '("heres" "some" "strings")))
27
+
28
+  (true-or-false? ___ (listp "a string"))
29
+  (true-or-false? ___ (atom "a string"))
30
+
31
+  (true-or-false? ___ (listp 2))
32
+  (true-or-false? ___ (atom 2))
33
+
34
+  (true-or-false? ___ (listp '(("first" "list") ("second" "list"))))
35
+  (true-or-false? ___ (atom '(("first" "list") ("second" "list")))))
36
+
37
+
38
+(define-test test-empty-list-is-both-list-and-atom
39
+    "the empty list, nil, is unique in that it is both a list and an atom"
40
+  (true-or-false? ___ (listp nil))
41
+  (true-or-false? ___ (atom nil)))
42
+
43
+
44
+(define-test test-keywords
45
+    "symbols like :hello or :like-this are treated differently in lisp.
46
+     Called keywords, they are symbols that evaluate to themselves."
47
+  (true-or-false? ___ (equal :this-is-a-keyword :this-is-a-keyword))
48
+  (true-or-false? ___ (equal :this-is-a-keyword ':this-is-a-keyword)))

+ 181 - 0
koans/clos.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; CLOS stands for Common Lisp Object System.
17
+;; CLOS is common lisps' object oriented framework.
18
+
19
+(defclass racecar () (color speed))
20
+
21
+(define-test test-defclass
22
+    (let ((car-1 (make-instance 'racecar))
23
+          (car-2 (make-instance 'racecar)))
24
+      (setf (slot-value car-1 'color) :red)
25
+      (setf (slot-value car-1 'speed) 220)
26
+      (setf (slot-value car-2 'color) :blue)
27
+      (setf (slot-value car-2 'speed) 240)
28
+      (assert-equal ____ (slot-value car-1 'color))
29
+      (assert-equal ____ (slot-value car-2 'speed))))
30
+
31
+;; CLOS provides functionality for creating getters / setters
32
+;; for defined objects
33
+
34
+(defclass spaceship ()
35
+  ((color :reader get-color :writer set-color)
36
+   (speed :reader get-speed :writer set-speed)))
37
+
38
+(define-test test-clos-getters-and-setters
39
+    (let ((ship-1 (make-instance 'spaceship)))
40
+      (set-color :orange ship-1)
41
+      (assert-equal ____ (get-color ship-1))
42
+      (set-speed 1000 ship-1)
43
+      (assert-equal ____ (get-speed ship-1))))
44
+
45
+;; CLOS also provides functionality to create accessors
46
+;; to object data.
47
+
48
+;; stores a value, and a counter which tallies accesses, read or write,
49
+;; to that value
50
+(defclass value-with-access-counter ()
51
+  ((value :reader get-value :writer set-value :initform 0)
52
+   (access-count :reader how-many-value-queries :initform 0)))
53
+
54
+(defmethod get-value ((object value-with-access-counter))
55
+           (incf (slot-value object 'access-count))
56
+           (slot-value object 'value))
57
+
58
+(defmethod set-value (new-value (object value-with-access-counter))
59
+           (incf (slot-value object 'access-count))
60
+           (setf (slot-value object 'value) new-value))
61
+
62
+(define-test test-access-counter
63
+    (let ((x (make-instance 'value-with-access-counter)))
64
+      ; check that no one has ever looked at the x value yet.
65
+      (assert-equal ____ (how-many-value-queries x))
66
+      ; check that the default value is zero.
67
+      (assert-equal ___ (get-value x))
68
+      ; now that we've looked at it, there is a single access.
69
+      (assert-equal ___ (how-many-value-queries x))
70
+      ; check that we can set and read the value
71
+      (set-value 33 x)
72
+      (assert-equal 33 (get-value x))
73
+      (assert-equal ___ (how-many-value-queries x))))
74
+
75
+
76
+; countdowner has a value which goes down every time you look at it
77
+; and returns "bang" when it hits zero.
78
+(defclass countdowner ()
79
+  ((value :initform 4)))
80
+
81
+;; Write the get-value for the countdowner
82
+;; to satisfy the test-countdowner tests.
83
+;; you may be interested in the 'decf function.
84
+(defmethod get-value ((object countdowner))
85
+  :WRITE-ME)
86
+
87
+
88
+(define-test test-countdowner
89
+    (let ((c (make-instance 'countdowner)))
90
+      (assert-equal 3 (get-value c))
91
+      (assert-equal 2 (get-value c))
92
+      (assert-equal 1 (get-value c))
93
+      (assert-equal "bang" (get-value c))
94
+      (assert-equal "bang" (get-value c))))
95
+
96
+
97
+;; Classes can inherit data and methods from other classes.
98
+;; Here, the specific CIRCLE class extends the generic SHAPE class
99
+(defclass shape ()
100
+  ((kind :reader get-kind :writer set-kind :initform :default-shape-kind)
101
+   (pos :reader get-pos :writer set-pos :initform '(0 0))))
102
+
103
+(defclass circle (shape)
104
+  ((radius :reader get-radius :writer set-radius :initform 0)))
105
+
106
+(define-test test-inheritance
107
+    (let ((circle-1 (make-instance 'circle))
108
+          (shape-1 (make-instance 'shape)))
109
+      (assert-equal ____ (type-of shape-1))
110
+      (assert-equal ____ (type-of circle-1))
111
+      (true-or-false? ____ (typep circle-1 'circle))
112
+      (true-or-false? ____ (typep circle-1 'shape))
113
+      (set-kind :circle circle-1)
114
+      (set-pos '(3 4) circle-1)
115
+      (set-radius 5 circle-1)
116
+      (assert-equal ____ (get-pos circle-1))
117
+      (assert-equal ____ (get-radius circle-1))))
118
+
119
+;; Classes may also inherit from more than one base class.
120
+;; This is known as multiple inheritance.
121
+
122
+;; Color holds an rgb triplet and a transparency alpha value.
123
+;; The RGB stands for the amount of red, green, and blue.
124
+;; the alpha (transparency) value is 0 for completely opaque.
125
+;; Note that color also has a kind, like shape.
126
+
127
+(defclass color ()
128
+  ((rgb :reader get-rgb :writer set-rgb :initform '(0 0 0))
129
+   (alpha :reader get-alpha :writer set-alpha :initform 0)
130
+   (kind :reader get-kind :writer set-kind :initform :default-color-kind)))
131
+
132
+;; The COLORED-CIRCLE class extends both CIRCLE and COLOR.
133
+;; Of particular interest is which "kind" slot will COLORED-CIRCLE get,
134
+;; since both CIRCLE and COLOR provide the "kind" slot.
135
+
136
+(defclass colored-circle (color circle) ())
137
+(defclass circled-color (circle color) ())
138
+
139
+(define-test test-multiple-inheritance
140
+    (let ((my-colored-circle (make-instance 'colored-circle))
141
+          (my-circled-color (make-instance 'circled-color)))
142
+      (assert-equal ____ (get-kind my-colored-circle))
143
+      (assert-equal ____ (get-kind my-circled-color))))
144
+
145
+
146
+(defvar *last-kind-accessor* nil)
147
+
148
+(defmethod get-kind ((object shape))
149
+           (setf *last-kind-accessor* :shape)
150
+           (slot-value object 'kind))
151
+
152
+(defmethod get-kind ((object circle))
153
+           (setf *last-kind-accessor* :circle)
154
+           (slot-value object 'kind))
155
+
156
+(defmethod get-kind ((object color))
157
+           (setf *last-kind-accessor* :color)
158
+           (slot-value object 'kind))
159
+
160
+;; Precedence order is similarly a depth first search for methods.
161
+
162
+(define-test test-multiple-inheritance-method-order
163
+    (let ((my-colored-circle (make-instance 'colored-circle))
164
+          (my-circled-color (make-instance 'circled-color))
165
+          (my-shape (make-instance 'shape))
166
+          (my-circle (make-instance 'circle))
167
+          (my-color (make-instance 'color)))
168
+      (get-kind my-shape)
169
+      (assert-equal ____ *last-kind-accessor*)
170
+      (get-kind my-circle)
171
+      (assert-equal ____ *last-kind-accessor*)
172
+      (get-kind my-color)
173
+      (assert-equal ____ *last-kind-accessor*)
174
+      (get-kind my-colored-circle)
175
+      (assert-equal ____ *last-kind-accessor*)
176
+      (get-kind my-circled-color)
177
+      (assert-equal ____ *last-kind-accessor*)))
178
+
179
+
180
+;; Todo: consider adding :before and :after method control instructions.
181
+

+ 126 - 0
koans/condition-handlers.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+"Common lisp conditions are much like CLOS classes.
17
+They are used to handle exceptional situations, and separate
18
+error handling code from normal operational code."
19
+
20
+(define-condition minimal-error-cond (error) ())
21
+(define-condition minimal-warning-cond (warning) ())
22
+
23
+
24
+(define-test test-conditions-derive-from-types
25
+    "conditions inherit from base types"
26
+  (true-or-false? ___ (typep (make-condition 'minimal-error-cond)
27
+                             'minimal-error-cond))
28
+
29
+  (true-or-false? ___ (typep (make-condition 'minimal-error-cond)
30
+                             'error))
31
+
32
+  (true-or-false? ___ (typep (make-condition 'minimal-error-cond)
33
+                             'warning))
34
+
35
+  (true-or-false? ___ (typep (make-condition 'minimal-warning-cond)
36
+                             'minimal-warning-cond))
37
+
38
+  (true-or-false? ___ (typep (make-condition 'minimal-warning-cond)
39
+                             'error))
40
+
41
+  (true-or-false? ___ (typep (make-condition 'minimal-warning-cond)
42
+                             'warning)))
43
+
44
+
45
+;; ----
46
+
47
+
48
+(define-condition my-div-by-zero-error (error) ())
49
+(define-condition my-non-number-args-error (error) ())
50
+
51
+(defun my-divide (num denom)
52
+  (if (or (not (numberp num))
53
+          (not (numberp denom)))
54
+      (error 'my-non-number-args-error))
55
+  (if (= 0 denom)
56
+      (error 'my-div-by-zero-error)
57
+      (/ num denom)))
58
+
59
+(define-test assert-error-thrown
60
+    "assert-error checks that the right error is thrown"
61
+  (assert-equal 3 (my-divide 6 2))
62
+  (assert-error 'my-div-by-zero-error (my-divide 6 0))
63
+  (assert-error ____ (my-divide 6 "zero")))
64
+
65
+
66
+(define-test test-handle-errors
67
+    "the handler case is like a case statement which can capture errors
68
+     and warnings, and execute appropriate forms in those conditions."
69
+  (assert-equal ___
70
+                (handler-case (my-divide 6 2)
71
+                  (my-div-by-zero-error (condition) :zero-div-error)
72
+                  (my-non-number-args-error (condition) :bad-args))
73
+  (assert-equal ___
74
+                (handler-case (my-divide 6 0)
75
+                  (my-div-by-zero-error (condition) :zero-div-error)
76
+                  (my-non-number-args-error (condition) :bad-args)))
77
+  (assert-equal ___
78
+                (handler-case (my-divide 6 "woops")
79
+                  (my-div-by-zero-error (condition) :zero-div-error)
80
+                  (my-non-number-args-error (condition) :bad-args)))))
81
+
82
+
83
+;; ----
84
+
85
+"conditions, as CLOS objects, can have slots, some of which have special
86
+meanings.  Common Lisp the Language Chapter 29 for more details.
87
+http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node312.html"
88
+
89
+; This error condition is more than a signal.  It carries data in two slots.
90
+; the "original-line" slot and the "reason" slot.  Both slots have a defined
91
+; :initarg, which they will use to set themselves, if available.  If not,
92
+; they have a default form (:initform).  They also both provide reader functions
93
+
94
+(define-condition logline-parse-error (error)
95
+  ((original-line :initarg :original-line :initform "line not given" :reader original-line)
96
+   (reason :initarg :reason :initform "no-reason" :reader reason)))
97
+
98
+
99
+;; This function is designed to take loglines, and report what type they are.
100
+;; It can also throw errors, like div-by-zero above, but the errors now carry some
101
+;;  additional information carried within the error itself.
102
+
103
+(defun get-logline-type (in-line)
104
+  (if (not (typep in-line 'string))
105
+      ;; if the in-line isn't a string, throw a logline-parse-error, and set the :reason and :original-line
106
+      (error 'logline-parse-error :original-line in-line :reason :bad-type-reason))
107
+  (cond
108
+    ((equal 0 (search "TIMESTAMP" in-line)) :timestamp-logline-type)
109
+    ((if (equal 0 (search "HTTP" in-line)) :http-logline-type))
110
+    ;; if we don't recognize the first token,  throw a logline-parse-error, and set the :reason and :original-line
111
+    (t (error 'logline-parse-error :original-line in-line :reason :unknown-token-reason))))
112
+
113
+
114
+(define-test test-errors-have-slots
115
+    (assert-equal ____
116
+                  (handler-case (get-logline-type "TIMESTAMP y13m01d03")
117
+                    (logline-parse-error (condition) (list (reason condition) (original-line condition)))))
118
+    (assert-equal ____
119
+                  (handler-case (get-logline-type "HTTP access 128.0.0.100")
120
+                    (logline-parse-error (condition) (list (reason condition) (original-line condition)))))
121
+    (assert-equal ____
122
+                  (handler-case (get-logline-type "bogus logline")
123
+                    (logline-parse-error (condition) (list (reason condition) (original-line condition)))))
124
+    (assert-equal ____
125
+                  (handler-case (get-logline-type 5555)
126
+                    (logline-parse-error (condition) (list (reason condition) (original-line condition))))))

+ 68 - 0
koans/control-statements.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+(define-test test-if-then-else
16
+    (let ((result))
17
+      (if t
18
+          (setf result "true value")
19
+          (setf result "false value"))
20
+      (assert-equal result ____)
21
+      (if nil
22
+          (setf result "true value")
23
+          (setf result "false value"))
24
+      (assert-equal result ____)))
25
+
26
+
27
+(define-test test-when-and-unless
28
+    (let ((result-1 nil)
29
+          (result-2 nil)
30
+          (when-nums nil)
31
+          (unless-nums nil))
32
+      (dolist (x '(1 2 3 4 5 6 7 8 9 10))
33
+        (when (> x 5)
34
+          (setf result-1 x)
35
+          (push x when-nums))
36
+        (unless (> x 5)
37
+          (setf result-2 x)
38
+          (push x unless-nums)))
39
+      (assert-equal result-1 ___)
40
+      (assert-equal result-2 ___)
41
+      (assert-equal when-nums ___)
42
+      (assert-equal unless-nums ___)))
43
+
44
+
45
+(define-test test-and-short-circuits
46
+    "and only evaluates forms until one evaluates to nil"
47
+  (assert-equal
48
+   ____
49
+   (let ((x 0))
50
+     (and
51
+      (setf x (+ 1 x))
52
+      (setf x (+ 1 x))
53
+      nil ;; <- ends execution of and.
54
+      (setf x (+ 1 x)))
55
+     x)))
56
+
57
+
58
+(define-test test-or-also-short-circuits
59
+    "or only evaluates until one argument evaluates to non-nil"
60
+  (assert-equal
61
+   ____
62
+   (let ((x 0))
63
+     (or
64
+      (setf x (+ 1 x))
65
+      (setf x (+ 1 x))
66
+      nil
67
+      (setf x (+ 1 x)))
68
+     x)))

+ 80 - 0
koans/dice-project.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+; based on about_dice_project.rb
17
+
18
+;; In this project we are going to build a CLOS class representing
19
+;; a simple set of dice.  There are only two operations on the dice,
20
+;; reading the values, and re-rolling.
21
+
22
+
23
+;;  YOU WRITE THIS PART:
24
+(defclass dice-set ()
25
+  () ;; WRITE DICE-SET CLASS BODY HERE
26
+)
27
+
28
+(defmethod get-values ((object dice-set))
29
+  ;; WRITE GET-VALUES METHOD DEFINITION HERE
30
+)
31
+
32
+(defmethod roll (how-many (object dice-set))
33
+  ;; WRITE ROLL METHOD DEFINITION HERE
34
+)
35
+
36
+
37
+(define-test test-create-dice-set
38
+;; tests making an instance of the dice-set
39
+    (let ((dice (make-instance 'dice-set)))
40
+      (assert-true dice)))
41
+
42
+
43
+(define-test test-rolling-the-dice-returns-a-set-of-integers-between-1-and-6
44
+;; tests rolling the dice
45
+    (let ((dice (make-instance 'dice-set)))
46
+      (roll 5 dice)
47
+      (assert-true (typep (get-values dice) 'list))
48
+      (assert-equal 5 (length (get-values dice)))
49
+      (dolist (x (get-values dice))
50
+        (assert-true (and (>= x 1)
51
+                          (<= x 6)
52
+                          (typep x 'integer))))))
53
+
54
+
55
+(define-test test-dice-values-do-not-change-unless-explicitly-rolled
56
+;; tests that dice don't change just by looking at them
57
+    (let ((dice (make-instance 'dice-set)))
58
+      (roll 100 dice)
59
+      (let ((first-time (get-values dice))
60
+            (second-time (get-values dice)))
61
+        (assert-equal first-time second-time))))
62
+
63
+
64
+(define-test test-dice-values-should-change-between-rolls
65
+;; tests that rolling the dice DOES change the values.
66
+    (let ((dice (make-instance 'dice-set))
67
+          (first-time nil)
68
+          (second-time nil))
69
+      (roll 100 dice)
70
+      (setf first-time (get-values dice))
71
+      (roll 100 dice)
72
+      (setf second-time (get-values dice))
73
+      (assert-false (equal first-time second-time))))
74
+
75
+(define-test test-you-can-roll-different-numbers-of-dice
76
+;; tests count parameter of how many dice to roll
77
+    (let ((dice (make-instance 'dice-set)))
78
+      (assert-equal 5 (length (roll 5 dice)))
79
+      (assert-equal 100 (length (roll 100 dice)))
80
+      (assert-equal 1 (length (roll 1 dice)))))

+ 81 - 0
koans/equality-distinctions.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+;; the most common equality predicates are eq, eql, equal and equalp
16
+;; eq is similar to comparing c pointers
17
+(define-test test-eq
18
+    "(eq x y) is true if and only if x and y are the same identical object
19
+     eq is like comparing pointers in c.  If the values are EQ, any non-nil
20
+     value may be returned."
21
+  (true-or-false? ___ (eq 'a 'a))
22
+  (true-or-false? ___ (eq 3 3.0))
23
+  (true-or-false? ___ (eq '(1 2) '(1 2)))
24
+  (true-or-false? ___ (eq "Foo" "Foo"))
25
+  (true-or-false? ___ (eq "Foo" (copy-seq "Foo")))
26
+  (true-or-false? ___ (eq "FOO" "Foo")))
27
+
28
+(define-test test-eql
29
+    "(eql x y) is true if (eq x y)
30
+     also it is true if x and y are numeric of the same type
31
+     and represent the same number.
32
+     (eql x y) also if x and y are the same characters."
33
+   (true-or-false? ___ (eql 'a 'a))
34
+   (true-or-false? ___ (eql 3 3))
35
+   (true-or-false? ___ (eql 3 3.0))
36
+   (true-or-false? ___ (eql '(1 2) '(1 2)))
37
+   (true-or-false? ___ (eql  '(:a . :b) '(:a . :b)))
38
+   (true-or-false? ___ (eql #\S #\S))
39
+   (true-or-false? ___ (eql "Foo" "Foo"))
40
+   (true-or-false? ___ (eql "Foo" (copy-seq "Foo")))
41
+   (true-or-false? ___ (eql "FOO" "Foo")))
42
+
43
+(define-test test-equal
44
+    "(equal x y) is true if (eql x y), or
45
+     x and y are lists with equal elements, or
46
+     x and y character or bit arrays with equal elements"
47
+   (true-or-false? ___ (equal 'a 'a))
48
+   (true-or-false? ___ (equal 3 3))
49
+   (true-or-false? ___ (equal 3 3.0))
50
+   (true-or-false? ___ (equal '(1 2) '(1 2)))
51
+   (true-or-false? ___ (equal  '(:a . :b) '(:a . :b)))
52
+   (true-or-false? ___ (equal  '(:a . :b) '(:a . :doesnt-match)))
53
+   (true-or-false? ___ (equal #\S #\S))
54
+   (true-or-false? ___ (equal "Foo" "Foo"))
55
+   (true-or-false? ___ (equal "Foo" (copy-seq "Foo")))
56
+   (true-or-false? ___ (equal "FOO" "Foo")))
57
+
58
+(define-test test-equalp
59
+    "(equalp x y) if (equal x y) or
60
+     if x and y are strings with the same characters (case independent).
61
+     if x and y are arrays with the same dimensions and equal elements
62
+     if x and y are numeric of different types but one may be upgraded to
63
+     the other type without loss and still exhibit equality."
64
+   (true-or-false? ___ (equalp 'a 'a))
65
+   (true-or-false? ___ (equalp 3 3))
66
+   (true-or-false? ___ (equalp 3 3.0))
67
+   (true-or-false? ___ (equalp '(1 2) '(1 2)))
68
+   (true-or-false? ___ (equalp  '(:a . :b) '(:a . :b)))
69
+   (true-or-false? ___ (equalp  '(:a . :b) '(:a . :doesnt-match)))
70
+   (true-or-false? ___ (equalp #\S #\S))
71
+   (true-or-false? ___ (equalp "Foo" "Foo"))
72
+   (true-or-false? ___ (equalp "Foo" (copy-seq "Foo")))
73
+   (true-or-false? ___ (equalp "FOO" "Foo")))
74
+
75
+(define-test test-numeric-equal
76
+    "(= x y) is only for numerics
77
+     and can take multiple arguments
78
+     if x or y is not numeric there will be a compiler error."
79
+   (true-or-false? ___ (= 99.0 99 99.000))
80
+   (true-or-false? ___ (= 0 1 -1))
81
+   (true-or-false? ___ (= (/ 2 3) (/ 6 9) (/ 86 129))))

+ 61 - 0
koans/evaluation.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; based on http://psg.com/~dlamkins/sl/chapter03-02.html
17
+
18
+(define-test test-function-name-is-first-argument
19
+    "In most imperative languages, the syntax of a function call has
20
+     the function name succeeded by a list of arguments.  In lisp,
21
+     the function name and arguments are all part of the same list,
22
+     with the function name the first element of that list."
23
+
24
+  "in these examples, the function names are +, -, and *"
25
+  (assert-equal ___ (+ 2 3))
26
+  (assert-equal ___ (- 1 3))
27
+  (assert-equal ___ (* 7 4))
28
+  "'>' and '=' are the boolean functions (predicates) 'greater-than' and
29
+   'equal to'"
30
+  (assert-equal ___ (> 100 4))
31
+  (assert-equal ___ (= 3 3))
32
+  "'NUMBERP' is a predicate which returns true if the argument is a number"
33
+  (assert-equal ___ (numberp 5))
34
+  (assert-equal ___ (numberp "five")))
35
+
36
+
37
+(define-test test-evaluation-order
38
+    "Arguments to functions are evaluated before the function"
39
+  (assert-equal ___ (* (+ 1 2) (- 13 10))))
40
+
41
+
42
+(define-test test-quoting-behavior
43
+    "Preceding a list with a quote (') will tell lisp not to evalute a list.
44
+     The quote special form suppresses normal evaluation, an instead returns
45
+     the literal list.
46
+     Evaluating the form (+ 1 2) returns the number 3,
47
+     but evaluating the form '(+ 1 2) returns the list (+ 1 2)"
48
+  (assert-equal ____ (+ 1 2))
49
+  (assert-equal ____ '(+ 1 2))
50
+  "'LISTP' is a predicate which returns true if the argument is a list"
51
+  " the '(CONTENTS) form defines a list literal containing CONTENTS"
52
+  (assert-equal ___ (listp '(1 2 3)))
53
+  (assert-equal ___ (listp 100))
54
+  (assert-equal ___ (listp "Word to your moms I came to drop bombs"))
55
+  (assert-equal ___ (listp nil))
56
+  (assert-equal ___ (listp (+ 1 2)))
57
+  (assert-equal ___ (listp '(+ 1 2)))
58
+  "equalp is an equality predicate"
59
+  (assert-equal ___ (equalp 3 (+ 1 2)))
60
+  "the '(xyz ghi) syntax is syntactic sugar for the (QUOTE (xyz ghi)) function."
61
+  (true-or-false? ___ (equalp '(/ 4 0) (quote (/ 4 0)))))

+ 8 - 0
koans/extra-credit.lsp

1
+;; EXTRA CREDIT:
2
+;;
3
+;; Create a program that will play the Greed Game.
4
+;; Rules for the game are in GREED_RULES.TXT.
5
+;;
6
+;; You already have a DiceSet class and score function you can use.
7
+;; Write a player class and a Game class to complete the project.  This
8
+;; is a free form assignment, so approach it however you desire.

+ 231 - 0
koans/functions.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+; borrows from about_methods.py
17
+
18
+(defun some-named-function (a b)
19
+  (+ a b))
20
+
21
+(define-test test-call-a-function
22
+    "DEFUN defines global functions"
23
+  (assert-equal ___ (some-named-function 7 11)))
24
+
25
+
26
+(define-test test-shadow-a-function
27
+    "Local functions are defined with FLET or LABELS.  One major difference
28
+     between the two is that local functions defined with LABELS may refer
29
+     to themselves, whereas local functions defined with FLET may not."
30
+   (assert-eq 18 (some-named-function 7 11))
31
+   "flet binds a function to a name within a lexical environment"
32
+   (flet ((some-named-function (a b) (* a b)))
33
+     (assert-equal ___ (some-named-function 7 11)))
34
+   (assert-equal ___  (some-named-function 7 11)))
35
+
36
+
37
+; borrowed from Common Lisp The Language chapter 5.2.2
38
+(defun func-with-opt-params (&optional (a 2) (b 3) )
39
+  ; each optional parameter has a form like (var default-val)
40
+  (list a b))
41
+
42
+(define-test test-optional-parameters
43
+    "Optional parameters are filled in with their default value."
44
+   (assert-equal (func-with-opt-params :test-1 :test-2) ___)
45
+   (assert-equal (func-with-opt-params :test-1) ___)
46
+   (assert-equal (func-with-opt-params) ___))
47
+
48
+
49
+;; ----
50
+
51
+
52
+(defun func-with-opt-params-and-indication (&optional (a 2 a?) (b 3 b?))
53
+  (list a a? b b?))
54
+
55
+(define-test test-optional-parameters-with-indication
56
+   "Common Lisp optional params may bind a symbol which indicate whether the
57
+    value was provided or defaulted.  Each optional parameter binding has the
58
+    form (var default-form supplied-p)."
59
+   (assert-equal (func-with-opt-params-and-indication :test-1 :test-2) ___)
60
+   (assert-equal (func-with-opt-params-and-indication :test-1) ___)
61
+   (assert-equal (func-with-opt-params-and-indication) ___))
62
+
63
+
64
+;; ----
65
+
66
+
67
+(defun func-with-rest-params (&rest x)
68
+  x)
69
+
70
+(define-test test-func-with-rest-params
71
+  "With &rest, the remaining params, are handed in as a list.  Remaining
72
+   arguments (possibly none) are collected into a list."
73
+  (assert-equal (func-with-rest-params) ___)
74
+  (assert-equal (func-with-rest-params 1) ___)
75
+   (assert-equal (func-with-rest-params 1 :two 333) ___))
76
+
77
+
78
+;; ----
79
+
80
+
81
+(defun func-with-key-params (&key a b)
82
+  (list a b))
83
+
84
+(defun test-key-params ()
85
+  "Key params allow the user to specify params in any order"
86
+   (assert-equal (func-with-key-params) ___)
87
+   (assert-equal (func-with-key-params :a 11 :b 22) ___)
88
+   ; it is not necessary to specify all key parameters
89
+   (assert-equal (func-with-key-params :b 22) ___)
90
+   ; order is not important
91
+   (assert-equal (func-with-key-params :b 22 :a 0) ___))
92
+
93
+(defun func-key-params-can-have-defaults (&key  (a 3 a?) (b 4 b?))
94
+  (list a a? b b?))
95
+
96
+(define-test test-key-params-can-have-defaults
97
+    "key parameters can have defaults also"
98
+   (assert-equal (func-key-params-can-have-defaults) ____)
99
+   (assert-equal (func-key-params-can-have-defaults :a 3 :b 4) ___)
100
+   (assert-equal (func-key-params-can-have-defaults :a 11 :b 22) ___)
101
+   (assert-equal (func-key-params-can-have-defaults :b 22) ___)
102
+   ; order is not important
103
+   (assert-equal (func-key-params-can-have-defaults :b 22 :a 0) ___))
104
+
105
+
106
+;; ----
107
+
108
+
109
+;; borrowed from common listp the language 5.2.2
110
+(defun func-with-funky-parameters (a &rest x &key b (c a))
111
+   (list a b c x))
112
+
113
+(define-test test-many-kinds-params
114
+    "CL provides the programmer with more than enough rope to hang himself."
115
+   (assert-equal (func-with-funky-parameters 1) ___)
116
+   (assert-equal (func-with-funky-parameters 1 :b 2) ___)
117
+   (assert-equal (func-with-funky-parameters 1 :b 2 :c 3) ___)
118
+   (assert-equal (func-with-funky-parameters 1 :c 3 :b 2) ___))
119
+
120
+
121
+;; Note that &rest parameters have to come before &key parameters.
122
+;; This is an error: (defun f (&key a &rest x) () )
123
+;; But this is ok:   (defun f (&rest x &key a) () )
124
+
125
+
126
+(define-test test-lambdas-are-nameless-functions
127
+    "A lambda form defines a function, but with no name.  It is possible
128
+     to execute that function immediately, or put it somewhere for later use."
129
+   (assert-equal 19 ((lambda (a b) (+ a b)) 10 9))
130
+  (let ((my-function))
131
+    (setf my-function (lambda (a b) (* a b)))
132
+    (assert-equal ___ (funcall my-function 11 9)))
133
+  (let ((list-of-functions nil))
134
+    (push (lambda (a b) (+ a b)) list-of-functions)
135
+    (push (lambda (a b) (* a b)) list-of-functions)
136
+    (push (lambda (a b) (- a b)) list-of-functions)
137
+    (assert-equal ___ (funcall (second list-of-functions) 2 33))))
138
+
139
+(define-test test-lambdas-can-have-optional-params
140
+   (assert-equal ___ ((lambda (a &optional (b 100)) (+ a b)) 10 9))
141
+   (assert-equal ___ ((lambda (a &optional (b 100)) (+ a b)) 10)))
142
+
143
+
144
+; returns sign x
145
+(defun sign-of (x)
146
+  (if (< x 0) (return-from where-to-return -1))
147
+  (if (eq x 0) (return-from where-to-return 0))
148
+  1)
149
+
150
+(define-test test-return-from-function-early
151
+   (assert-equal (sign-of -5.5) ___)
152
+   (assert-equal (sign-of 0) ___)
153
+   (assert-equal (sign-of ___) 1))
154
+
155
+
156
+;; ----
157
+
158
+
159
+;; Lambdas create "lexical closures", meaning that the resulting function, when
160
+;; called, will execute in an environment wherein the lexical bindings to all
161
+;; referred to names still apply.
162
+;; This example from "Common Lisp The Language" Ch. 7
163
+
164
+(defun adder (x)
165
+  "The result of (adder n) is a nameless function with one parameter.
166
+  This function will add n to its argument."
167
+  (lambda (y) (+ x y)))
168
+
169
+(defun test-lexical-closure-over-adder ()
170
+  (let ((add-100 (adder 100))
171
+        (add-500 (adder 500)))
172
+  "add-100 and add-500 now refer to different bindings to x"
173
+   (assert-equal ___ (funcall add-100 3))
174
+   (assert-equal ___ (funcall add-500 3))))
175
+
176
+
177
+;; ----
178
+
179
+
180
+;; The closure gives the returned function access to the bindings, not just the
181
+;; values.  This means that two functions which close over the same variables
182
+;; will always see the same values of those variables if one does a setq.
183
+
184
+(defun two-funs (x)
185
+  "Returns a list of two functions.
186
+   The first takes no parameters and returns x.
187
+   The second takes one parameter, y, and resets x to the value of y."
188
+  (list (function (lambda () x))
189
+        (function (lambda (y) (setq x y)))))
190
+
191
+(define-test test-lexical-closure-interactions
192
+    "An illustration of how lexical closures may interact."
193
+  (let ((tangled-funs-1 (two-funs 1))
194
+        (tangled-funs-2 (two-funs 2)))
195
+     (assert-equal (funcall (first tangled-funs-1)) ___)
196
+     (funcall (second tangled-funs-1) 0)
197
+     (assert-equal (funcall (first tangled-funs-1)) ___)
198
+
199
+     (assert-equal (funcall (first tangled-funs-2)) ___)
200
+     (funcall (second tangled-funs-2) 100)
201
+     (assert-equal (funcall (first tangled-funs-2)) ___)))
202
+
203
+
204
+(define-test test-apply-function-with-apply
205
+  "APPLY calls the function parameter on a list of all the remaining
206
+   parameters"
207
+  (let (f1 f2 f3)
208
+    (setq f1 '+)
209
+    (setq f2 '-)
210
+    (setq f3 'max)
211
+
212
+    (assert-equal ___ (apply f1 '(1 2)))
213
+    (assert-equal ___ (apply f2 '(1 2)))
214
+
215
+    ; after the function name, the parameters are consed onto the front
216
+    ; of the very last parameter
217
+    (assert-equal ___ (apply f1 1 2 '(3)))
218
+    (assert-equal ___ (apply f3 1 2 3 4 '()))))
219
+
220
+
221
+(define-test test-apply-function-with-funcall
222
+  "FUNCALL calls the function parameter on a list of all the remaining
223
+   parameters.  Remaining params do not expect a final list."
224
+  (let (f1 f2 f3)
225
+    (setq f1 '+)
226
+    (setq f2 '-)
227
+    (setq f3 'max)
228
+    (assert-equal ___ (funcall f1 1 2))
229
+    (assert-equal ___ (funcall f2 1 2))
230
+    (assert-equal ___ (funcall f1 1 2 3))
231
+    (assert-equal ___ (funcall f3 1 2 3 4))))

+ 128 - 0
koans/hash-tables.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+; based on python koans: about_dictionaries.py
17
+
18
+
19
+(define-test test-create-hash-table
20
+    "make hash table with make-hash-table"
21
+  (let ((my-hash-table))
22
+    (setf my-hash-table (make-hash-table))
23
+    (true-or-false? ___ (typep my-hash-table 'hash-table))
24
+    (true-or-false? ___  (hash-table-p my-hash-table))
25
+    (true-or-false? ___  (hash-table-p (make-array '(3 3 3))))
26
+    (assert-equal ___ (hash-table-count my-hash-table))))
27
+
28
+
29
+(define-test test-hash-table-access
30
+    "gethash is for accessing hash tables"
31
+  (let ((table-of-cube-roots (make-hash-table)))
32
+
33
+  "assign the key-value pair 1->'uno'"
34
+  (setf (gethash 1 table-of-cube-roots) 1)
35
+  (assert-equal 1 (gethash 1 table-of-cube-roots))
36
+  (assert-equal 1 (hash-table-count table-of-cube-roots))
37
+
38
+  (setf (gethash 8 table-of-cube-roots) 2)
39
+  (setf (gethash -27 table-of-cube-roots) -3)
40
+  (assert-equal ___ (gethash -3 table-of-cube-roots))
41
+  (assert-equal ___ (hash-table-count table-of-cube-roots))
42
+
43
+  "accessing unset keys returns nil"
44
+  (assert-equal ___ (gethash 125 table-of-cube-roots))))
45
+
46
+
47
+(define-test test-hash-key-equality
48
+    "hash tables need to know how to tell if two keys are equivalent.
49
+     The programmer must be careful to know which equality predicate is right."
50
+  (let ((hash-table-eq nil)
51
+        (hash-table-equal nil)
52
+        (hash-table-default nil))
53
+
54
+    "define three hash tables, with different equality tests"
55
+    (setf hash-table-eq (make-hash-table :test #'eq))
56
+    (setf hash-table-equal (make-hash-table :test #'equal))
57
+    (setf hash-table-default (make-hash-table))
58
+
59
+    "add the same string twice, to each"
60
+    (setf (gethash "one" hash-table-eq) "uno")
61
+    (setf (gethash "one" hash-table-eq) "uno")
62
+
63
+    (setf (gethash "one" hash-table-equal) "uno")
64
+    (setf (gethash "one" hash-table-equal) "uno")
65
+
66
+    (setf (gethash "one" hash-table-default) "uno")
67
+    (setf (gethash "one" hash-table-default) "uno")
68
+
69
+    "count how many unique key-value pairs in each"
70
+    (assert-equal ___ (hash-table-count hash-table-eq))
71
+    (assert-equal ___ (hash-table-count hash-table-equal))
72
+    (assert-equal ___ (hash-table-count hash-table-default))))
73
+
74
+
75
+(define-test test-hash-table-equality
76
+    (let ((h1 (make-hash-table :test #'equal))
77
+          (h2 (make-hash-table :test #'equal)))
78
+      (setf (gethash "one" h1) "yat")
79
+      (setf (gethash "one" h2) "yat")
80
+      (setf (gethash "two" h1) "yi")
81
+      (setf (gethash "two" h2) "yi")
82
+      (true-or-false? ___ (eq h1 h2))
83
+      (true-or-false? ___ (equal h1 h2))
84
+      (true-or-false? ___ (equalp h1 h2))))
85
+
86
+
87
+(define-test test-changing-hash-tables
88
+    (let ((babel-fish (make-hash-table :test #'equal))
89
+          (expected (make-hash-table :test #'equal)))
90
+      (setf (gethash "one" babel-fish) "uno")
91
+      (setf (gethash "two" babel-fish) "dos")
92
+      (setf (gethash "one" expected) "ein")
93
+      (setf (gethash "two" expected) "zwei")
94
+
95
+      (setf (gethash "one" babel-fish) "ein")
96
+      (setf (gethash "two" babel-fish) ____)
97
+
98
+      (assert-true (equalp babel-fish expected))))
99
+
100
+
101
+(define-test test-hash-key-membership
102
+    "hash tables use multiple value return to tell you if the key exists"
103
+    (let ((prev-pres (make-hash-table :test #'equal))
104
+          (value-and-exists nil))
105
+      (setf (gethash "Obama" prev-pres) "Bush")
106
+      (setf (gethash "Lincoln" prev-pres) "Buchanan")
107
+      (setf (gethash "Washington" prev-pres) nil)
108
+
109
+      (setf value-and-exists (multiple-value-list (gethash "Obama" prev-pres)))
110
+      (assert-equal value-and-exists '("Bush" t))
111
+      (setf value-and-exists (multiple-value-list (gethash "Lincoln" prev-pres)))
112
+      (assert-equal value-and-exists ____)
113
+      (setf value-and-exists (multiple-value-list (gethash "Washington" prev-pres)))
114
+      (assert-equal value-and-exists ____)
115
+      (setf value-and-exists (multiple-value-list (gethash "Franklin" prev-pres)))
116
+      (assert-equal value-and-exists ____)))
117
+
118
+
119
+(define-test test-make-your-own-hash-table
120
+    "make a hash table that meets the following conditions"
121
+  (let ((colors (make-hash-table))
122
+        (values (make-hash-table)))
123
+
124
+    (assert-equal (hash-table-count colors) 4)
125
+    (setf values (list (gethash "blue" colors)
126
+                       (gethash "green" colors)
127
+                       (gethash "red" colors)))
128
+    (assert-equal values '((0 0 1) (0 1 0) (1 0 0)))))

+ 116 - 0
koans/iteration.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; There are many options for iteration in lisp.
17
+;; This set of koans will introduce a few of the most common ones
18
+
19
+
20
+;; Dolist evaluates a form for every element om a list.
21
+
22
+(defvar some-primes '(10301 11311 19991 999565999))
23
+
24
+(define-test test-dolist
25
+    "'dolist' iterates over values in a list, binding each value to a lexical
26
+      variable in turn"
27
+  (let ((how-many-in-list 0)
28
+        (biggest-in-list (first some-primes)))
29
+    "this dolist loops over the some-primes, defined above"
30
+    (dolist (one-prime some-primes)
31
+      (if (> one-prime biggest-in-list)
32
+          (setf biggest-in-list one-prime))
33
+      (incf how-many-in-list))
34
+    (assert-equal ___ how-many-in-list)
35
+    (assert-equal ___ biggest-in-list))
36
+  (let ((sum 0))
37
+    "write your own do-list here to calculate the sum of some-primes"
38
+    "you may be interested in investigating the 'incf' function"
39
+    ;(dolist ... )
40
+    (assert-equal 999607602 sum)))
41
+
42
+
43
+(define-test test-dolist-with-return
44
+    "Dolist can accept a return variable, which will be the return value
45
+     upon completion of the iteration."
46
+    (let ((my-list '(1 2 3 4))
47
+          (my-return))
48
+      (dolist (x my-list my-return)
49
+        (push (* x x) my-return))
50
+      (assert-equal ____ my-return)))
51
+
52
+
53
+(define-test test-dotimes
54
+    "'dotimes' iterates over the integers from 0 to (limit - 1),
55
+      binding them in order to your selected symbol."
56
+    (let ((out-list nil))
57
+      (dotimes (y 3) (push y out-list))
58
+      (assert-equal out-list ___)))
59
+
60
+
61
+(defvar *x* "global")
62
+(define-test test-dotimes-binding
63
+    "dotimes establishes a local lexical binding which may shadow
64
+     a global value."
65
+  (dotimes (*x* 4)
66
+    (true-or-false? ___ (equal "global" *x*)))
67
+  (true-or-false? ___ (equal "global" *x*)))
68
+
69
+
70
+(define-test test-loop-until-return
71
+    "Loop loops forever, unless some return condition is executed.
72
+     Note that the loop macro includes many additional options,
73
+     which will be covered in a future koan."
74
+    (let ((loop-counter 0))
75
+      (loop
76
+        (incf loop-counter)
77
+        (if (>= loop-counter 100) (return loop-counter)))
78
+      (assert-equal ___ loop-counter)))
79
+
80
+
81
+(define-test test-mapcar
82
+    "mapcar takes a list an a function.  It returns a new list
83
+     with the function applied to each element of the input"
84
+  (let ((mc-result (mapcar #'evenp '(1 2 3 4 5))))
85
+    (assert-equal mc-result ____)))
86
+
87
+
88
+;; ----
89
+
90
+
91
+(defun vowelp (c)
92
+  "returns true iff c is a vowel"
93
+  (find c "AEIOUaeiou"))
94
+
95
+(defun vowels-to-xs (my-string)
96
+  "converts all vowels in a string to the character 'x'"
97
+  (coerce
98
+   (loop for c across my-string
99
+         with new-c
100
+         do (setf new-c (if (vowelp c) #\x c))
101
+         collect new-c)
102
+   'string))
103
+
104
+(define-test test-mapcar-with-defun
105
+  "mapcar is a convenient way to apply a function to a collection"
106
+  (assert-equal (vowels-to-xs "Astronomy") "xstrxnxmy")
107
+  (let* ((subjects '("Astronomy" "Biology" "Chemistry" "Linguistics"))
108
+         (mc-result (mapcar #'vowels-to-xs subjects)))
109
+    (assert-equal mc-result ____)))
110
+
111
+
112
+;; ----
113
+
114
+(define-test test-mapcar-with-lambda
115
+    (let ((mc-result (mapcar #'(lambda (x) (mod x 10)) '(21 152 403 14))))
116
+      (assert-equal mc-result ____)))

+ 109 - 0
koans/lists.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; based on python koans 'about_lists.py'
17
+;; based also on "Lisp 3rd addition" ch. 17. "List storage, surgery and reclamation"
18
+
19
+
20
+(define-test test-creating-lists
21
+    "lists can be created using the quote form, or the 'list' function"
22
+  (let ((fruits nil)
23
+        (some-evens nil))
24
+    (setf fruits '(orange pomello clementine))
25
+    (setf some-evens (list (* 2 1) (* 2 2) (* 2 3)))
26
+    (assert-equal fruits ___)
27
+    (assert-equal ___ (length fruits))))
28
+
29
+
30
+(define-test test-list-cons
31
+    "cons CONStructs new lists, by prefixing some list with
32
+     a new element like (cons new-element some-list)"
33
+    (let ((nums nil))
34
+      (setf nums (cons :one nums))
35
+      (assert-equal '(:one) nums)
36
+
37
+      (setf nums (cons :two nums))
38
+      (assert-equal ___ nums)
39
+
40
+      "lists can contain anything, even mixtures of different things"
41
+      (setf nums (cons 333 nums))
42
+      (assert-equal ___ nums)
43
+
44
+      "lists can of course contain lists"
45
+      (setf nums (cons '("the" "rest") nums))
46
+      (assert-equal ___ nums)))
47
+
48
+
49
+(define-test test-push-pop
50
+    (let ((stack '(10 20 30 40))
51
+          (firstval nil))
52
+      "push adds an element to the beginning of a list referred to by some symbol"
53
+      (push "last" stack)
54
+      (assert-equal '("last" 10 20 30 40) stack)
55
+
56
+       "pop is the opposite of push.
57
+       It removes and returns the first element of a list"
58
+      (setf firstval (pop stack))
59
+      (assert-equal "last" firstval)
60
+      (assert-equal '(10 20 30 40) stack)
61
+
62
+      (setf firstval (pop stack))
63
+      (assert-equal ___ firstval)
64
+      (assert-equal ___ stack)))
65
+
66
+
67
+(define-test test-append
68
+    "append attatches one list ot the end of another."
69
+  (assert-equal '(:a :b :c) (append '(:a :b) '(:c)))
70
+
71
+  (let ((abc '(:a :b :c))
72
+        (xyz '(:x :y :z))
73
+        (abcxyz nil))
74
+    (setf abcxyz (append abc xyz))
75
+    (assert-equal ___ abc)
76
+    (assert-equal ___ xyz)
77
+    (assert-equal ___ abcxyz)))
78
+
79
+
80
+(define-test test-accessing-list-elements
81
+    (let ((noms '("peanut" "butter" "and" "jelly")))
82
+      (assert-equal "peanut" (first noms))
83
+      (assert-equal ___ (second noms))
84
+      (assert-equal ___ (fourth noms))
85
+      "last returns a singleton list of the final element"
86
+      (assert-equal ___ (last noms))
87
+      (assert-equal "butter" (nth 1 noms)) ; k 1
88
+      (assert-equal ___ (nth 0 noms))
89
+      (assert-equal ___ (nth 2 noms))
90
+      "'elt' is similar to 'nth', with the arguments reversed"
91
+      (assert-equal ___ (elt noms 2))))
92
+
93
+
94
+(define-test test-slicing-lists
95
+    (let ((noms '("peanut" "butter" "and" "jelly")))
96
+      (assert-equal ___ (subseq noms 0 1))
97
+      (assert-equal ___ (subseq noms 0 2))
98
+      (assert-equal ___ (subseq noms 2 2))
99
+      (assert-equal ___ (subseq noms 2))))
100
+
101
+
102
+(define-test test-list-breakdown
103
+    "car (aka. 'first') returns the first value in a list"
104
+  (assert-equal ___ (car '(1 2 3)))
105
+  (assert-equal ___ (car nil))
106
+    "cdr (aka. 'rest') refers to the remainder of the list,
107
+     after the first element"
108
+  (assert-equal ___ (cdr '(1 2 3)))
109
+  (assert-equal ___ (cdr nil)))

+ 165 - 0
koans/loops.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+;; see http://www.gigamonkeys.com/book/loop-for-black-belts.html
16
+;; "Loop for blackbelts" for more on the loop macro.
17
+
18
+(define-test test-basic-loop
19
+    (let* ((letters '(:a :b :c :d))
20
+           (loop-result
21
+             (loop for letter in letters
22
+                   collect letter)))
23
+      (assert-equal loop-result ____)))
24
+
25
+
26
+(define-test test-compound-loop
27
+    (let* ((letters '(:a :b :c :d))
28
+           (loop-result
29
+             (loop for letter in letters
30
+                   for i from 1 to 1000
31
+                   collect (list i letter))))
32
+      (assert-equal loop-result ____)))
33
+
34
+
35
+(define-test test-counting-loop-skip-by-syntax
36
+   "with multiple 'for' clauses, loop ends when the first is exhausted"
37
+    (let* ((letters '(:a :b :c :d))
38
+           (loop-result
39
+             (loop for letter in letters
40
+                   for i from 0 to 1000 by 5
41
+                   collect (list i letter))))
42
+      (assert-equal loop-result ____ )))
43
+
44
+
45
+(define-test test-counting-backwards
46
+    (let ((loop-result
47
+             (loop for i from 10 downto -10 by 5
48
+                   collect i )))
49
+      (assert-equal loop-result ____ )))
50
+
51
+
52
+(define-test test-loop-in-vs-loop-on
53
+    (let* ((letters '(:a :b :c))
54
+           (loop-result-in
55
+            (loop for letter in letters collect letter))
56
+           (loop-result-on
57
+            (loop for letter on letters collect letter)))
58
+      (assert-equal loop-result-in ____)
59
+      (assert-equal loop-result-on ____ )))
60
+
61
+
62
+(define-test test-loop-in-skip-by
63
+    (let* ((letters '(:a :b :c :d :e :f))
64
+           (loop-result-in
65
+            (loop for letter in letters collect letter))
66
+           (loop-result-in-cdr
67
+            (loop for letter in letters by #'cdr collect letter))
68
+           (loop-result-in-cddr
69
+            (loop for letter in letters by #'cddr collect letter))
70
+           (loop-result-in-cdddr
71
+            (loop for letter in letters by #'cdddr collect letter)))
72
+      (assert-equal loop-result-in ____)
73
+      (assert-equal loop-result-in-cdr ____)
74
+      (assert-equal loop-result-in-cddr ____)
75
+      (assert-equal loop-result-in-cdddr ____)))
76
+
77
+
78
+(define-test test-loop-across-vector
79
+    (let* ((my-vector (make-array '(5) :initial-contents '(0 1 2 3 4)))
80
+           (loop-result
81
+            (loop for val across my-vector collect val)))
82
+      (assert-equal ____ loop-result)))
83
+
84
+
85
+(define-test test-loop-across-2d-array
86
+    (let* ((my-array (make-array '(3 3) :initial-contents '((0 1 2) (3 4 5) (6 7 8))))
87
+           (loop-result
88
+            (loop for i from 0 below (array-total-size my-array) collect (row-major-aref my-array i))))
89
+      (assert-equal loop-result ____ )))
90
+
91
+
92
+(define-test test-loop-across-2d-array-respecting-shape
93
+    (let* ((my-array (make-array '(3 2) :initial-contents '((0 1) (2 3) (4 5))))
94
+           (loop-result
95
+            (loop for i from 0 below (array-dimension my-array 0) collect
96
+              (loop for j from 0 below (array-dimension my-array 1) collect
97
+                (expt (aref my-array i j) 2)))))
98
+      (assert-equal loop-result ____ )))
99
+
100
+
101
+(defvar books-to-heros)
102
+(setf books-to-heros (make-hash-table :test 'equal))
103
+(setf (gethash "The Hobbit" books-to-heros) "Bilbo")
104
+(setf (gethash "Where The Wild Things Are" books-to-heros) "Max")
105
+(setf (gethash "The Wizard Of Oz" books-to-heros) "Dorothy")
106
+(setf (gethash "The Great Gatsby" books-to-heros) "James Gatz")
107
+
108
+
109
+(define-test test-loop-over-hash-tables
110
+    (let* ((pairs-in-table
111
+            (loop for k being the hash-keys in books-to-heros
112
+                  using (hash-value v)
113
+                  collect (list k v))))
114
+      (assert-equal ____ (length pairs-in-table))
115
+      (true-or-false? ____ (find '("The Hobbit" "Bilbo") pairs-in-table :test #'equal))))
116
+
117
+
118
+(define-test test-value-accumulation-forms
119
+    (let ((loop-1
120
+           (loop for x in '(1 2 4 8 16)
121
+                 collect x into collected
122
+                   count x into counted
123
+                 sum x into summed
124
+                 maximize x into maximized
125
+                 minimize x into minimized
126
+                 finally (return (list collected counted summed maximized minimized)))))
127
+      (destructuring-bind (col count sum max min) loop-1
128
+        (assert-equal col ____)
129
+        (assert-equal count ____)
130
+        (assert-equal sum ____)
131
+        (assert-equal max ____)
132
+        (assert-equal min ____))))
133
+
134
+
135
+(define-test test-destructuring-bind
136
+    (let* ((count 0)
137
+           (result (loop for (a b) in '((1 9) (2 8) (3 7) (4 6))
138
+                        do (setf count (+ 1 count))
139
+                         collect (+ a b))))
140
+      (assert-equal ____ count)
141
+      (assert-equal ____ result)))
142
+
143
+
144
+(define-test test-conditional-execution
145
+    (let ((loop-return
146
+           (loop for x in '(1 1 2 3 5 8 13)
147
+                 when (evenp x) sum x)))
148
+      (assert-equal loop-return ____)))
149
+
150
+
151
+(defun greater-than-10-p (x)
152
+  (> x 10))
153
+
154
+(define-test test-conditional-with-defun
155
+    (let ((loop-return
156
+           (loop for x in '(1 1 2 3 5 8 13)
157
+                 when (greater-than-10-p x) sum x)))
158
+      (assert-equal loop-return ____)))
159
+
160
+
161
+(define-test test-conditional-with-lambda
162
+    (let ((loop-return
163
+           (loop for x in '(1 1 2 3 5 8 13)
164
+                 when ((lambda (z) (equal 1 (mod z 3))) x) sum x)))
165
+      (assert-equal loop-return ____)))

+ 162 - 0
koans/macros.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; A lisp macro is like a function which takes an input lisp form
17
+;; and produces a new output lisp form.  Calling the macro
18
+;; first produces new form, and then evaluates it in the context
19
+;; of the macro call.  The first phase, the creation of the new
20
+;; macro form, is called 'macro expansion'.
21
+
22
+
23
+
24
+(defmacro repeat-2 (f) (list 'progn f f))
25
+
26
+(define-test test-macro-expands
27
+    "assert-expands checks the expanded macro form against expectation."
28
+  (assert-expands
29
+   '(progn (do-something arg1 arg2) (do-something arg1 arg2))
30
+   (repeat-2 (do-something arg1 arg2)))
31
+
32
+  (assert-expands
33
+   ____
34
+   (repeat-2 (setf x (+ 1 x)))))
35
+
36
+
37
+;; ----
38
+
39
+
40
+(define-test test-backtick-form
41
+    "backtick (`) form is much like single-quote (') form, except that subforms
42
+     preceded by a comma (,) are evaluated, rather then left as literals"
43
+  (let ((num 5)
44
+        (word 'dolphin))
45
+    (true-or-false? ___  (equal '(1 3 5) `(1 3 5)))
46
+    (true-or-false? ___  (equal '(1 3 5) `(1 3 num)))
47
+    (assert-equal ____ `(1 3 ,num))
48
+    (assert-equal ____ `(word ,word ,word word))))
49
+
50
+
51
+(define-test test-at-form
52
+    "The at form, (@) in the backtick context splices a list variables into
53
+     the form."
54
+    (let ((axis '(x y z)))
55
+      (assert-equal '(x y z) axis)
56
+      (assert-equal '(the axis are (x y z)) `(the axis are ,axis))
57
+      (assert-equal '(the axis are x y z) `(the axis are ,@axis)))
58
+    (let ((coordinates '((43.15 77.6) (42.36 71.06))))
59
+      (assert-equal ____
60
+        `(the coordinates are ,coordinates))
61
+      (assert-equal ____
62
+        `(the coordinates are ,@coordinates))))
63
+
64
+
65
+;; ---- On Gensym: based on ideas from common lisp cookbook
66
+
67
+;; sets sym1 and sym2 to val
68
+(defmacro double-setf-BAD (sym1 sym2 val)
69
+  `(progn (setf ,sym1 ,val) (setf ,sym2 ,val)))
70
+
71
+(define-test test-no-gensym
72
+    "macro expansions may introduce difficult to see
73
+     interactions"
74
+  (let ((x 0)
75
+        (y 0))
76
+    (double-setf-BAD x y 10)
77
+    (assert-equal x 10)
78
+    (assert-equal y 10))
79
+
80
+  (let ((x 0)
81
+        (y 0))
82
+    (double-setf-BAD x y (+ x 100))
83
+    (assert-equal x ____)
84
+    (assert-equal y ____)))
85
+
86
+;; sets sym1 and sym2 to val
87
+(defmacro double-setf-SAFER (sym1 sym2 val)
88
+  (let ((new-fresh-symbol (gensym)))
89
+    `(let ((,new-fresh-symbol ,val))
90
+       (progn (setf ,sym1 ,new-fresh-symbol) (setf ,sym2 ,new-fresh-symbol)))))
91
+
92
+(define-test test-with-gensym
93
+    "gensym creates a new symbol."
94
+  (let ((x 0)
95
+        (y 0))
96
+    (double-setf-SAFER x y 10)
97
+    (assert-equal x 10)
98
+    (assert-equal y 10))
99
+
100
+  (let ((x 0)
101
+        (y 0))
102
+    (double-setf-SAFER x y (+ x 100))
103
+    (assert-equal x ____)
104
+    (assert-equal y ____)))
105
+
106
+
107
+;; ----
108
+
109
+(defvar *log* nil)
110
+
111
+(defmacro log-form (&body body)
112
+  "records the body form to the list *log* and then evalues the body normally"
113
+  `(let ((retval ,@body))
114
+     (push ',@body *log*)
115
+     retval))
116
+
117
+(define-test test-basic-log-form
118
+  "illustrates how the basic log-form macro above works"
119
+  (assert-equal 1978 (* 2 23 43))
120
+  (assert-equal nil *log*)
121
+  "log-form does not interfere with the usual return value"
122
+  (assert-equal 1978 (log-form (* 2 23 43)))
123
+  "log-form records the code which it has been passed"
124
+  (assert-equal ___ (length *log*))
125
+  (assert-equal ___ (first *log*))
126
+  "macros evaluating to more macros is ok, if confusing"
127
+  (assert-equal 35 (log-form (log-form (- 2013 1978))))
128
+  (assert-equal 3 (length *log*))
129
+  (assert-equal '(log-form (- 2013 1978)) (first *log*))
130
+  (assert-equal '(- 2013 1978) (second *log*)))
131
+
132
+;; Now you must write a more advanced log-form, that also records the value
133
+;; returned by the form
134
+
135
+(defvar *log-with-value* nil)
136
+
137
+;; you must write this macro
138
+(defmacro log-form-with-value (&body body)
139
+  "records the body form, and the form's return value
140
+   to the list *log-with-value* and then evalues the body normally"
141
+  `(let ((logform nil)
142
+         (retval ,@body))
143
+
144
+     ;; YOUR MACRO COMPLETION CODE GOES HERE.
145
+
146
+     retval))
147
+
148
+
149
+
150
+(define-test test-log-form-and-value
151
+    "log should start out empty"
152
+  (assert-equal nil *log-with-value*)
153
+  "log-form-with-value does not interfere with the usual return value"
154
+  (assert-equal 1978 (log-form-with-value (* 2 23 43)))
155
+  "log-form records the code which it has been passed"
156
+  (assert-equal 1 (length *log-with-value*))
157
+  (assert-equal '(:form (* 2 23 43) :value 1978) (first *log-with-value*))
158
+  "macros evaluating to more macros is ok, if confusing"
159
+  (assert-equal 35 (log-form-with-value (log-form-with-value (- 2013 1978))))
160
+  (assert-equal 3 (length *log-with-value*))
161
+  (assert-equal '(:form (log-form-with-value (- 2013 1978)) :value 35) (first *log-with-value*))
162
+  (assert-equal '(:form (- 2013 1978) :value 35) (second *log-with-value*)))

+ 82 - 0
koans/mapcar-and-reduce.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+(define-test test-mapcar-basics
16
+    "We can apply a function to each member
17
+     of a list using mapcar."
18
+  (defun times-two (x) (* x 2))
19
+  (assert-equal ____ (mapcar #'times-two '(1 2 3)))
20
+  (assert-equal ____ (mapcar #'first '((3 2 1) 
21
+                                      ("little" "small" "tiny") 
22
+                                      ("pigs" "hogs" "swine")))))
23
+
24
+
25
+(define-test test-mapcar-multiple-lists
26
+    "The mapcar function can be applied to
27
+     more than one list. It applies a function
28
+     to successive elements of the lists."
29
+  (assert-equal ____ (mapcar #'* '(1 2 3) '(4 5 6)))
30
+  (assert-equal ____ (mapcar #'list '("lisp" "are") '("koans" "fun"))))
31
+
32
+
33
+(define-test test-transpose-using-mapcar
34
+    "Replace WRONG-FUNCTION with the correct function (don't forget
35
+     the #') to take the 'transpose'."
36
+  (defun WRONG-FUNCTION-1 (&rest rest) '())
37
+  (defun transpose (L) (apply #'mapcar (cons #'WRONG-FUNCTION-1 L)))
38
+    (assert-equal '((1 4 7)
39
+                  (2 5 8) 
40
+                  (3 6 9)) 
41
+                (transpose '((1 2 3) 
42
+                             (4 5 6) 
43
+                             (7 8 9))))
44
+  (assert-equal '(("these" "pretzels" "are")
45
+                  ("making" "me" "thirsty"))
46
+                (transpose '(("these" "making")
47
+                             ("pretzels" "me")
48
+                            ("are" "thirsty")))))
49
+
50
+
51
+(define-test test-reduce-basics
52
+    "The reduce function applies uses a supplied
53
+     binary function to combine the elements of a
54
+     list from left to right."
55
+  (assert-equal ___  (reduce #'+ '(1 2 3 4)))
56
+  (assert-equal ___ (reduce #'expt '(2 3 2))))
57
+
58
+
59
+(define-test test-reduce-right-to-left
60
+    "The keyword :from-end allows us to apply
61
+     reduce from right to left."
62
+  (assert-equal ___ (reduce #'+ '(1 2 3 4) :from-end t))
63
+  (assert-equal ___ (reduce #'expt '(2 3 2) :from-end t)))
64
+
65
+
66
+(define-test test-reduce-with-initial-value
67
+    "We can supply an initial value to reduce."
68
+  (assert-equal ___ (reduce #'expt '(10 21 34 43) :initial-value 1))
69
+  (assert-equal ___ (reduce #'expt '(10 21 34 43) :initial-value 0)))
70
+
71
+
72
+(defun WRONG-FUNCTION-2 (a b) (a))
73
+(defun WRONG-FUNCTION-3 (a b) (a))
74
+
75
+(define-test test-mapcar-and-reduce
76
+    "mapcar and reduce are a powerful combination.
77
+     insert the correct function names, instead of INCORRECT-FUNCTION-X
78
+     to define an inner product."
79
+  (defun inner (x y) 
80
+    (reduce #'WRONG-FUNCTION-2 (mapcar #'WRONG-FUNCTION-3 x y)))
81
+  (assert-equal 32 (inner '(1 2 3) '(4 5 6)))
82
+  (assert-equal 310 (inner '(10 20 30) '(4 3 7))))

+ 48 - 0
koans/multiple-values.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+
17
+"In lisp, it is possible for a function to return more than one value.
18
+This is distinct from returning a list or structure of values."
19
+
20
+(define-test test-floor-returns-multiple-values
21
+    (let ((x)
22
+          (y))
23
+      (setf x (floor 1.5))
24
+      (assert-equal x 1)
25
+      (setf x (multiple-value-list (floor 3/2)))
26
+      (assert-equal x '(1 1/2)))
27
+  (assert-equal (multiple-value-list (floor 99/4)) ____))
28
+
29
+(defun next-fib (a b)
30
+  (values b (+ a b)))
31
+
32
+(define-test test-multi-value-bind
33
+    (let ((x)
34
+          (y))
35
+      (setf x (next-fib 2 3))
36
+      (assert-equal x ___)
37
+      (setf x (multiple-value-list (next-fib 2 3)))
38
+      (assert-equal x ___)
39
+      "multiple value bind binds the variables in the first form
40
+       to the outputs of the second form.  And then returns the output
41
+       of the third form using those bindings"
42
+      (setf y (multiple-value-bind (b c) (next-fib 3 5) (* b c)))
43
+      (assert-equal y ___)
44
+      "multiple-value-setq is like setf, but can set multiple variables"
45
+      (multiple-value-setq (x y) (values :v1 :v2))
46
+      (assert-equal (list x y) '(:v1 :v2))
47
+      (multiple-value-setq (x y) (next-fib 5 8))
48
+      (assert-equal (list x y) ____)))

+ 55 - 0
koans/nil-false-empty.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+(define-test test-t-and-nil-are-opposites
16
+    "not is a function which returns the boolean opposite of its argument"
17
+   (true-or-false? ___ (not nil))
18
+   (true-or-false? ___ (not t)))
19
+
20
+
21
+(define-test test-nil-and-empty-list-are-the-same-thing
22
+  (true-or-false? ___ ())
23
+  (true-or-false? ___ (not ())))
24
+
25
+
26
+(define-test test-lots-of-things-are-true
27
+   " every value, other than nil, is boolean true"
28
+   (true-or-false? ___ 5)
29
+   (true-or-false? ___ (not 5))
30
+   (true-or-false? ___ "A String")
31
+   "only nil is nil.  Everything else is effectively true."
32
+   "the empty string"
33
+   (true-or-false? ___ "")
34
+   "a list containing a nil"
35
+   (true-or-false? ___ '(nil))
36
+   "an array with no elements"
37
+   (true-or-false? ___ (make-array '(0)))
38
+   "the number zero"
39
+   (true-or-false? ___ 0))
40
+
41
+
42
+(define-test test-and
43
+   "and can take multiple arguments"
44
+   (true-or-false? ___ (and t t t t t))
45
+   (true-or-false? ___ (and t t nil t t))
46
+   "if no nils, and returns the last value"
47
+   (assert-equal ___ (and t t t t t 5)))
48
+
49
+
50
+(define-test test-or
51
+   "or can also take multiple arguments"
52
+   (true-or-false? ____  (or nil nil nil t nil))
53
+   "or returns the first non nil value, or nil if there are none."
54
+   (assert-equal ____ (or nil nil nil))
55
+   (assert-equal ____ (or 1 2 3 4 5)))

+ 69 - 0
koans/scope-and-extent.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+(defun shadow-z (z)
17
+;; reuses the symbol name z to build a return value
18
+;; returns a list like (value-of-z, 2) 
19
+  (cons z
20
+        (cons (let ((z 2)) z)
21
+              nil)))
22
+
23
+(define-test test-shadowing-a-variable
24
+  (assert-equal ___ (shadow-z 1)))
25
+
26
+
27
+(defun code-block-01 ()
28
+;; illustrates a basic property of code-blocks
29
+  (block here
30
+    (return-from here 4)
31
+    5))
32
+
33
+(defun code-block-02 ()
34
+  (block outer
35
+    (block inner
36
+      (return-from outer 'space)
37
+      (return-from inner 'tube))
38
+    (return-from outer 'valve)))
39
+
40
+(define-test test-code-block-01
41
+  (assert-equal ___ (code-block-01)))
42
+
43
+(define-test test-code-block-02
44
+  (assert-equal ___ (code-block-02)))
45
+
46
+
47
+;; About closures and the distinction of lexical and dynamic bindings
48
+
49
+;; this recipe from stackoverflow
50
+;; http://stackoverflow.com/questions/463463/dynamic-and-lexical-variables-in-common-lisp
51
+; (print "no special x: a typical closure.")
52
+
53
+;; bind f to a function which depends on a local variable x
54
+;; then invoke f to see which value of x is returned.
55
+
56
+(define-test test-lexical-bindings-may-be-shadowed
57
+  (assert-eq ___ (let ((f (let ((x 10))
58
+                 (lambda () x))))  ; <-- x bound lexically
59
+    (let ((x 20))          ; form 2
60
+      (funcall f)))))
61
+
62
+
63
+(define-test test-special-bindings-look-back-on-execution-path
64
+  (assert-eq ___ (let ((f (let ((x 10))
65
+             (declare (special x))
66
+             (lambda () x))))      ; <-- x bound dynamically
67
+    (let ((x 20))          ; form 2
68
+      (declare (special x))
69
+    (funcall f)))))

+ 85 - 0
koans/scoring-project.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;;;;;;;;;;;;;;
17
+;; GREED !! ;;
18
+;;;;;;;;;;;;;;
19
+
20
+
21
+;; Modified from Ruby Koans: about_scoring_project.rb
22
+
23
+; *Greed* is a dice game where you roll up to five dice to accumulate
24
+; points.  The following "score" function will be used to calculate the
25
+; score of a single roll of the dice.
26
+;
27
+; A greed roll is scored as follows:
28
+;
29
+; * A set of three ones is 1000 points
30
+;
31
+; * A set of three numbers (other than ones) is worth 100 times the
32
+;   number. (e.g. three fives is 500 points).
33
+;
34
+; * A one (that is not part of a set of three) is worth 100 points.
35
+;
36
+; * A five (that is not part of a set of three) is worth 50 points.
37
+;
38
+; * Everything else is worth 0 points.
39
+;
40
+;
41
+; Examples:
42
+;
43
+; score([1,1,1,5,1]) => 1150 points
44
+; score([2,3,4,6,2]) => 0 points
45
+; score([3,4,5,3,3]) => 350 points
46
+; score([1,5,1,2,4]) => 250 points
47
+;
48
+; More scoring examples are given in the tests below:
49
+;
50
+; Your goal is to write the score method.
51
+
52
+(defun score (dice)
53
+  ; You need to write this method
54
+)
55
+
56
+(define-test test-score-of-an-empty-list-is-zero
57
+    (assert-equal 0 (score nil)))
58
+
59
+(define-test test-score-of-a-single-roll-of-5-is-50
60
+    (assert-equal 50 (score '(5))))
61
+
62
+
63
+(define-test test-score-of-a-single-roll-of-1-is-100
64
+    (assert-equal 100 (score '(1))))
65
+
66
+(define-test test-score-of-multiple-1s-and-5s-is-the-sum-of-individual-scores
67
+    (assert-equal 300 (score '(1 5 5 1))))
68
+
69
+(define-test test-score-of-single-2s-3s-4s-and-6s-are-zero
70
+    (assert-equal 0 (score '(2 3 4 6))))
71
+
72
+
73
+(define-test test-score-of-a-triple-1-is-1000
74
+    (assert-equal 1000  (score '(1 1 1))))
75
+
76
+(define-test test-score-of-other-triples-is-100x
77
+    (assert-equal 200  (score '(2 2 2)))
78
+    (assert-equal 300  (score '(3 3 3)))
79
+    (assert-equal 400  (score '(4 4 4)))
80
+    (assert-equal 500  (score '(5 5 5)))
81
+    (assert-equal 600  (score '(6 6 6))))
82
+
83
+(define-test test-score-of-mixed-is-sum
84
+    (assert-equal 250  (score '(2 5 2 2 3)))
85
+    (assert-equal 550  (score '(5 5 5 5))))

+ 118 - 0
koans/special-forms.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+; Special forms are evaluatable lisp forms (lists) which are
17
+; neither functions nor macros.  Here is an introduction to a
18
+; few of them.
19
+
20
+; based on http://psg.com/~dlamkins/sl/chapter03-03.html
21
+
22
+(defvar my-name)
23
+(defvar my-clones-name)
24
+(defvar a)
25
+(defvar b)
26
+(defvar c 0)
27
+
28
+(define-test test-setf
29
+    "setf is used to assign values to symbols.  These symbols my refer to
30
+     variables with lexical or dynamic scope."
31
+  (setf my-name "David")
32
+  (assert-equal my-name ____)
33
+  " In SBCL, if the symbol isn't defined as a variable, via a top-level defvar
34
+  or let statement, the setf call may result in a warning."
35
+  (setf my-clones-name my-name)
36
+  (assert-equal "David" ____)
37
+  (setf a 5)
38
+  (setf b 10)
39
+  (setf c ___)
40
+  (assert-equal 50 c))
41
+
42
+
43
+(define-test test-let
44
+    "The let form establishes a lexical extent, within which explicit symbols
45
+     may be bound to values.  The binding only extends over the extent of the
46
+     lexical form.  After which, the previous value, if it exists, is visible again."
47
+  (setf a 10)
48
+  (setf b 20)
49
+  (assert-equal a ___)
50
+  (assert-equal b ___)
51
+  (let ((a 1111)
52
+        (b 2222))
53
+    (assert-equal a ___)
54
+    (assert-equal b ___))
55
+  (assert-equal a ___)
56
+  (assert-equal b ___))
57
+
58
+
59
+(define-test test-let-default-value
60
+    "let vars have a default value"
61
+    (let ((x))
62
+      (assert-equal ___ x)))
63
+
64
+(define-test test-let-bindings-are-parallel
65
+    "When defining the bindings in the let form, later bindings may not depend
66
+     on earlier ones"
67
+  (setf a 100)
68
+  (let ((a 5)
69
+        (b (* 10 a)))
70
+    (assert-equal b ___)))
71
+
72
+(define-test test-let*-bindings-are-series
73
+    "let* is like let, but successive bindings may use values of previous ones"
74
+  (setf a 100)
75
+  (let* ((a 5)
76
+         (b (* 10 a)))
77
+    (assert-equal b ___))
78
+  (assert-equal a ___))
79
+
80
+
81
+(define-test write-your-own-let-statement
82
+    "fix the let statement to get the tests to pass"
83
+  (setf a 100)
84
+  (setf b 23)
85
+  (setf c 456)
86
+  (let ((a 0)
87
+        (b __)
88
+        (c __))
89
+    (assert-equal a 100)
90
+    (assert-equal b 200)
91
+    (assert-equal c "Jellyfish"))
92
+  (let* ((a 0))
93
+    (assert-equal a 121)
94
+    (assert-equal b 200)
95
+    (assert-equal c (+ a (/ b a)))))
96
+
97
+
98
+(define-test test-cond
99
+    "the cond form is like the c switch statement"
100
+  (setf a 4)
101
+  (setf c
102
+        (cond ((> a 0) :positive)
103
+              ((< a 0) :negative)
104
+              (t :zero)))
105
+  (assert-equal ____ c))
106
+
107
+
108
+(defun cartoon-dads (input)
109
+  " you should be able to complete this cond statement"
110
+  (cond ((equal input :this-one-doesnt-happen) :fancy-cat)
111
+        (t :unknown)))
112
+
113
+(define-test test-your-own-cond-statement
114
+    "fix this by completing the 'cartoon-dads' function above"
115
+  (assert-equal (cartoon-dads :bart) :homer)
116
+  (assert-equal (cartoon-dads :stewie) :peter)
117
+  (assert-equal (cartoon-dads :stan) :randy)
118
+  (assert-equal (cartoon-dads :space-ghost) :unknown))

+ 78 - 0
koans/strings.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+(define-test test-double-quoted-strings-are-strings
16
+    (let ((my-string "do or do not"))
17
+      (true-or-false? ___ (typep my-string 'string))
18
+      "strings are the same thing as vectors of characters"
19
+      (true-or-false? ___ (typep my-string 'array))
20
+      (assert-equal (aref "meat" 2) (aref "fiesta" 5))
21
+      "strings are not integers :p"
22
+      (true-or-false? ___ (typep my-string 'integer))))
23
+
24
+
25
+(define-test test-multi-line-strings-are-strings
26
+    (let ((my-string "this is
27
+                      a multi
28
+                      line string"))
29
+      (true-or-false? ___ (typep my-string 'string))))
30
+
31
+
32
+(define-test test-escape-quotes
33
+    (let ((my-string "this string has one of these \" in it"))
34
+      (true-or-false? ___ (typep my-string 'string))))
35
+
36
+
37
+; This test from common lisp cookbook
38
+(define-test test-substrings
39
+    "since strings are sequences, you may use subseq"
40
+  (let ((my-string "Groucho Marx"))
41
+    (assert-equal "Marx" (subseq my-string 8))
42
+    (assert-equal (subseq my-string 0 7) ____)
43
+    (assert-equal (subseq my-string 1 5) ____)))
44
+
45
+(define-test test-accessing-individual-characters
46
+  "char literals look like this"
47
+  (true-or-false? ___ (typep #\a 'character))
48
+  (true-or-false? ___ (typep "A" 'character))
49
+  (true-or-false? ___ (typep #\a 'string))
50
+  "char is used to access individual characters"
51
+  (let ((my-string "Cookie Monster"))
52
+    (assert-equal (char my-string 0) #\C)
53
+    (assert-equal (char my-string 3) #\k)
54
+    (assert-equal (char my-string 7) ___)))
55
+
56
+
57
+(define-test test-concatenating-strings
58
+    "concatenating strings in lisp is a little cumbersome"
59
+  (let ((a "this")
60
+        (b "is")
61
+        (c "unwieldly"))
62
+    (assert-equal ___ (concatenate 'string a " " b " " c))))
63
+
64
+
65
+(define-test test-searching-for-characters
66
+    "you can use position to detect characters in strings
67
+     (or elements of sequences)"
68
+  (assert-equal ___ (position #\b "abc"))
69
+  (assert-equal ___ (position #\c "abc"))
70
+  (assert-equal ___ (find #\d "abc")))
71
+
72
+
73
+(define-test test-finding-substrings
74
+    "search finds subsequences"
75
+  (let ((title "A supposedly fun thing I'll never do again"))
76
+    (assert-equal 2 (search "supposedly" title))
77
+    (assert-equal 12 (search "CHANGETHISWORD" title))))
78
+

+ 104 - 0
koans/structures.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+;; Lisp structures encapsulate data which belongs together.  They are
17
+;; a template of sorts, providing a way to generate multiple instances of
18
+;; uniformly organized information
19
+;;
20
+;; Defining a struct also interns accessor functions to get and set the fields
21
+;; of the structure.
22
+
23
+
24
+;; Define a new struct with the defstruct form.  The following call creates a
25
+;; new structure type named basketball-player, with slots named:
26
+;; 'name', 'team', and number.
27
+(defstruct basketball-player name team number)
28
+
29
+(define-test test-make-struct
30
+    ;; Create a basketball structure instance, and then read out the values.
31
+  (let ((player-1 (make-basketball-player
32
+                   :name "larry" :team :celtics :number 33)))
33
+    (assert-equal "larry" (basketball-player-name player-1))
34
+    (assert-equal ___ (basketball-player-team player-1))
35
+    (assert-equal ___ (basketball-player-number player-1))
36
+    (assert-equal 'basketball-player (type-of player-1))
37
+    (setf (basketball-player-team player-1) :RETIRED)
38
+    (assert-equal ___ (basketball-player-team player-1))))
39
+
40
+
41
+;; Struct fields can have default values
42
+;; fields without explicit defaults default to nil.
43
+
44
+(defstruct baseball-player name (position :outfield) (team :red-sox))
45
+
46
+(define-test test-struct-defaults
47
+    (let ((player-2 (make-baseball-player)))
48
+      (assert-equal ___ (baseball-player-position player-2))
49
+      (assert-equal ___ (baseball-player-team player-2))
50
+      (assert-equal ___ (baseball-player-name player-2))))
51
+
52
+
53
+;; The accessor names can get pretty long.  It's possible to specify
54
+;; a nickname to make code readable with the :conc-name option.
55
+
56
+(defstruct (american-football-player (:conc-name nfl-guy-)) name position team)
57
+
58
+(define-test test-abbreviated-struct-access
59
+    (let ((player-3 (make-american-football-player
60
+                     :name "Drew Brees" :position :QB :team "Saints")))
61
+      (assert-equal ___ (nfl-guy-position player-3))))
62
+
63
+
64
+;; Structs can be defined as EXTENSIONS to previous structures.
65
+;; This form of inheritance allows composition of objects.
66
+
67
+(defstruct (nba-contract (:include basketball-player)) salary start-year end-year)
68
+
69
+(define-test test-structure-extension
70
+    (let ((contract-1 (make-nba-contract
71
+                       :salary 136000000
72
+                       :start-year 2004
73
+                       :end-year 2011
74
+                       :name "Kobe Bryant"
75
+                       :team :LAKERS
76
+                       :number 24)))
77
+      (assert-equal ___ (nba-contract-start-year contract-1))
78
+      (assert-equal ___ (type-of contract-1))
79
+      ;; do inherited structures follow the rules of type hierarchy?
80
+      (true-or-false? ___ (typep contract-1 'BASKETBALL-PLAYER))
81
+      ;; can you access structure fields with the inherited accessors?
82
+      (assert-equal ___ (nba-contract-team contract-1))
83
+      (assert-equal ___ (basketball-player-team contract-1))))
84
+
85
+
86
+;; Copying of structs is handled with the copy-{name} form.  Note that
87
+;; copying is shallow.
88
+
89
+(define-test test-structure-copying
90
+    (let ((manning-1 (make-american-football-player :name "Manning" :team '("Colts" "Broncos")))
91
+          (manning-2 (make-american-football-player :name "Manning" :team '("Colts" "Broncos"))))
92
+      ;; manning-1 and manning-2 are different objects
93
+      (true-or-false? ___ (eq manning-1 manning-2))
94
+      ;; but manning-1 and manning-2 contain the same information
95
+      ;; (note the equalp instead of eq
96
+      (true-or-false? ___ (equalp manning-1 manning-2))
97
+      ;; copied structs are much the same.
98
+      (true-or-false? ___ (equalp manning-1 (copy-american-football-player manning-1)))
99
+      (true-or-false? ___ (eq     manning-1 (copy-american-football-player manning-1)))
100
+      ;; note that the copying is shallow
101
+      (let ((shallow-copy (copy-american-football-player manning-1)))
102
+        (setf (car (nfl-guy-team manning-1)) "Giants")
103
+        (assert-equal ___ (car (nfl-guy-team manning-1)))
104
+        (assert-equal ___ (car (nfl-guy-team shallow-copy))))))

+ 316 - 0
koans/threads.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+;; NOTE: This koan group uses language features specific to sbcl, that are 
16
+;; not part of the Common Lisp specification.  If you are not using sbcl, 
17
+;; feel free to skip this group by removing it from '.koans'
18
+
19
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20
+;; Making threads with sb-thread:make-thread  ;;
21
+;; Joining threads with sb-thread:join-thread ;;
22
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
+
24
+;; sb-thread takes a -function- as a parameter.
25
+;; This function will be executed in a separate thread.
26
+
27
+;; Since the execution order of separate threads is not guaranteed,
28
+;; we must -join- the threads in order to make our assertions.
29
+
30
+(defvar *greeting* "no greeting")
31
+
32
+(defun sets-socal-greeting ()
33
+  (setf *greeting* "Sup, dudes"))
34
+
35
+(define-test test-hello-world-thread
36
+    "Create a thread which returns 'hello world', then ends.
37
+    using a lambda as the supplied function to execute."
38
+  (assert-equal *greeting* "no greeting")
39
+  (let ((greeting-thread
40
+         (sb-thread:make-thread
41
+          (lambda ()
42
+            (setf *greeting* "hello world")))))
43
+    (sb-thread:join-thread greeting-thread)
44
+    (assert-equal *greeting* "hello world")
45
+    (setf greeting-thread (sb-thread:make-thread #'sets-socal-greeting))
46
+    (sb-thread:join-thread greeting-thread)
47
+    (assert-equal *greeting* ____)))
48
+
49
+
50
+(define-test test-join-thread-return-value
51
+    "the return value of the thread is passed in sb-thread:join-thread"
52
+  (let ((my-thread (sb-thread:make-thread
53
+                    (lambda () (* 11 99)))))
54
+    (assert-equal ____ (sb-thread:join-thread my-thread))))
55
+
56
+
57
+(define-test test-threads-can-have-names
58
+    "Threads can have names.  Names can be useful in diagnosing problems
59
+     or reporting."
60
+  (let ((empty-plus-thread
61
+         (sb-thread:make-thread #'+
62
+                                :name "what is the sum of no things adding?")))
63
+    (assert-equal (sb-thread:thread-name empty-plus-thread)
64
+                  ____)))
65
+
66
+
67
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
68
+;; Sending arguments to the thread function: ;;
69
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
70
+
71
+(defun returns-hello-name (name)
72
+  (format nil "Hello, ~a" name))
73
+
74
+(defun double-wrap-list (x y z)
75
+  (list (list x y z)))
76
+
77
+;; Create a thread which will print out "Hello -Name-" using
78
+;; the named write-hello-name function.   Arguments are handed
79
+;; to threads as a list, unless there is just a single argument
80
+;; then it does not need to be wrapped in a list.
81
+
82
+(define-test test-sending-arguments-to-thread
83
+    (assert-equal "Hello, Buster" 
84
+                  (sb-thread:join-thread
85
+                   (sb-thread:make-thread 'returns-hello-name
86
+                                          :arguments "Buster")))
87
+    (assert-equal ____
88
+                  (sb-thread:join-thread
89
+                   (sb-thread:make-thread 'double-wrap-list
90
+                                          :arguments '(3 4 5)))))
91
+
92
+
93
+;; ----
94
+
95
+(defvar *accum* 0)
96
+
97
+(defun accum-after-time (time arg1)
98
+    "sleeps for time seconds and then adds arg1 to *accum*"
99
+  (sleep time)
100
+  (incf *accum* arg1))
101
+
102
+(defvar *before-time-millisec* 0)
103
+(defvar *after-time-millisec* 0)
104
+
105
+;; cheap and dirty time measuring function
106
+(defun duration-ms ()
107
+  (- *after-time-millisec* *before-time-millisec*))
108
+
109
+(define-test test-run-in-series
110
+    "get internal real time returns a time stamp in milliseconds"
111
+  (setf *accum* 0)
112
+  (setf *before-time-millisec* (get-internal-real-time))
113
+  (accum-after-time 0.3 1)
114
+  (accum-after-time 0.2 2)
115
+  (accum-after-time 0.1 4)
116
+  (setf *after-time-millisec* (get-internal-real-time))
117
+  (true-or-false? ___ (> (duration-ms) 500))
118
+  (true-or-false? ___ (< (duration-ms) 700))
119
+  (assert-equal *accum* ___))
120
+
121
+(define-test test-run-in-parallel
122
+    "same program as above, executed in threads.  Sleeps are simultaneous"
123
+  (setf *accum* 0)
124
+  (setf *before-time-millisec* (get-internal-real-time))
125
+  (let ((thread-1 (sb-thread:make-thread 'accum-after-time :arguments '(0.3 1)))
126
+        (thread-2 (sb-thread:make-thread 'accum-after-time :arguments '(0.2 2)))
127
+        (thread-3 (sb-thread:make-thread 'accum-after-time :arguments '(0.1 4))))
128
+    (sb-thread:join-thread thread-1)
129
+    (sb-thread:join-thread thread-2)
130
+    (sb-thread:join-thread thread-3))
131
+  (setf *after-time-millisec* (get-internal-real-time))
132
+  (true-or-false? ___ (> (duration-ms) 200))
133
+  (true-or-false? ___  (< (duration-ms) 400))
134
+  (assert-equal *accum* ___))
135
+
136
+
137
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
138
+;; killing renegade threads            ;;
139
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
140
+
141
+
142
+(defun spawn-looping-thread (name)
143
+  "create a never-ending looping thread with a given name"
144
+  (sb-thread:make-thread (lambda () (loop)) :name name))
145
+
146
+(defvar *top-thread* sb-thread:*current-thread*)
147
+(defun main-thread-p (thread) (eq thread *top-thread*))
148
+
149
+(defun kill-thread-if-not-main (thread)
150
+" kills a given thread, unless the thread is the main thread.
151
+ returns nil if thread is main.
152
+ returns a 'terminated~' string otherwise"
153
+  (unless (main-thread-p thread)
154
+    (sb-thread:terminate-thread thread)
155
+    (concatenate 'string "terminated " (sb-thread:thread-name thread))))
156
+
157
+(defun kill-spawned-threads ()
158
+  "kill all lisp threads except the main thread."
159
+  (map 'list 'kill-thread-if-not-main (sb-thread:list-all-threads)))
160
+
161
+(defun spawn-three-loopers ()
162
+  "Spawn three run-aways."
163
+  (progn
164
+    (spawn-looping-thread "looper one")
165
+    (spawn-looping-thread "looper two")
166
+    (spawn-looping-thread "looper three")))
167
+
168
+(define-test test-counting-and-killing-threads
169
+    "list-all-threads makes a list of all running threads in this lisp.  The sleep
170
+     calls are necessary, as killed threads are not instantly removed from the
171
+     list of all running threads."
172
+  (assert-equal ___ (length (sb-thread:list-all-threads)))
173
+  (kill-thread-if-not-main (spawn-looping-thread "NEVER CATCH ME~!  NYA NYA!"))
174
+  (sleep 0.01)
175
+  (assert-equal ___ (length (sb-thread:list-all-threads)))
176
+  (spawn-three-loopers)
177
+  (assert-equal ___ (length (sb-thread:list-all-threads)))
178
+  (kill-spawned-threads)
179
+  (sleep 0.01)
180
+  (assert-equal ___ (length (sb-thread:list-all-threads))))
181
+
182
+
183
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
184
+;; bindings are not inherited across threads ;;
185
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
186
+
187
+(defvar *v* 0)
188
+
189
+(defun returns-v ()
190
+  *v*)
191
+
192
+(define-test test-threads-dont-get-bindings
193
+    "bindings are not inherited across threads"
194
+  (let ((thread-ret-val (sb-thread:join-thread
195
+                         (sb-thread:make-thread 'returns-v))))
196
+    (assert-equal thread-ret-val ____))
197
+  (let ((*v* "LEXICAL BOUND VALUE"))
198
+    (assert-equal *v* ____)
199
+    (let ((thread-ret-val (sb-thread:join-thread
200
+                           (sb-thread:make-thread 'returns-v))))
201
+      (assert-equal thread-ret-val ____))))
202
+
203
+
204
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
205
+;; global state (special vars) are ;;
206
+;; shared across threads           ;;
207
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
208
+
209
+(defvar *g* 0)
210
+
211
+(defun waits-and-increments-g (&optional (n 0.2))
212
+  "sets *g* to 1 + the value of *g* n seconds ago"
213
+  (let ((my-remembered-g *g*))
214
+    (sleep n)
215
+    (setq *g* (+ 1 my-remembered-g))))
216
+
217
+(define-test test-serial-wait-and-increment
218
+ "incrementing *g* three times and expecting
219
+  the final value to be three works."
220
+  (setf *g* 0)
221
+  (waits-and-increments-g)
222
+  (waits-and-increments-g)
223
+  (waits-and-increments-g)
224
+  (assert-equal *g* ___))
225
+
226
+
227
+(define-test test-parallel-wait-and-increment
228
+    (setf *g* 0)
229
+  (let ((thread-1 (sb-thread:make-thread 'waits-and-increments-g))
230
+        (thread-2 (sb-thread:make-thread 'waits-and-increments-g))
231
+        (thread-3 (sb-thread:make-thread 'waits-and-increments-g)))
232
+    (sb-thread:join-thread thread-1)
233
+    (sb-thread:join-thread thread-2)
234
+    (sb-thread:join-thread thread-3)
235
+    (assert-equal *g* ___)))
236
+
237
+
238
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
239
+;; Global state can be protected ;;
240
+;; with a mutex.                 ;;
241
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
242
+
243
+(setf *g* 0)
244
+(defvar *gs-mutex* (sb-thread:make-mutex :name "g's lock"))
245
+
246
+(defun protected-increments-g (&optional (n 0.1))
247
+  "Surround all references to *g* within the with-mutex form."
248
+  (sb-thread:with-mutex (*gs-mutex*)
249
+    (let ((my-remembered-g *g*))
250
+      (sleep n)
251
+      (setq *g* (+ 1 my-remembered-g)))))
252
+
253
+(define-test test-parallel-wait-and-increment-with-mutex
254
+    (setf *g* 0)
255
+  (let ((thread-1 (sb-thread:make-thread 'protected-increments-g))
256
+        (thread-2 (sb-thread:make-thread 'protected-increments-g))
257
+        (thread-3 (sb-thread:make-thread 'protected-increments-g)))
258
+    (sb-thread:join-thread thread-1)
259
+    (sb-thread:join-thread thread-2)
260
+    (sb-thread:join-thread thread-3)
261
+    (assert-equal *g* ___)))
262
+
263
+;;;;;;;;;;;;;;;;
264
+;; Semaphores ;;
265
+;;;;;;;;;;;;;;;;
266
+
267
+;; Incrementing a semaphore is an atomic operation.
268
+(defvar *g-semaphore* (sb-thread:make-semaphore :name "g" :count 0))
269
+
270
+(defun semaphore-increments-g ()
271
+  (sb-thread:signal-semaphore *g-semaphore*))
272
+
273
+(define-test test-increment-semaphore
274
+    (assert-equal 0 (sb-thread:semaphore-count *g-semaphore*))
275
+  (sb-thread:join-thread (sb-thread:make-thread 'semaphore-increments-g :name "S incrementor 1"))
276
+  (sb-thread:join-thread (sb-thread:make-thread 'semaphore-increments-g :name "S incrementor 2"))
277
+  (sb-thread:join-thread (sb-thread:make-thread 'semaphore-increments-g :name "S incrementor 3"))
278
+  (assert-equal ___ (sb-thread:semaphore-count *g-semaphore*)))
279
+
280
+
281
+;; Semaphores can be used to manage resource allocation, and to trigger
282
+;; threads to run when the semaphore value is above zero.
283
+
284
+(defvar *apples* (sb-thread:make-semaphore :name "how many apples" :count 0))
285
+(defvar *orchard-log* (make-array 10))
286
+(defvar *next-log-idx* 0)
287
+(defvar *orchard-log-mutex* (sb-thread:make-mutex :name "orchard log mutex"))
288
+
289
+(defun add-to-log (item)
290
+  (sb-thread:with-mutex (*orchard-log-mutex*)
291
+    (setf (aref *orchard-log* *next-log-idx*) item)
292
+    (incf *next-log-idx*)))
293
+
294
+(defun apple-eater ()
295
+  (sb-thread:wait-on-semaphore *apples*)
296
+  (add-to-log "apple eaten."))
297
+
298
+(defun apple-grower ()
299
+  (sleep 0.1)
300
+  (add-to-log "apple grown.")
301
+  (sb-thread:signal-semaphore *apples*))
302
+
303
+(defun num-apples ()
304
+  (sb-thread:semaphore-count *apples*))
305
+
306
+(define-test test-orchard-simulation
307
+    (assert-equal (num-apples) ___)
308
+  (let ((eater-thread (sb-thread:make-thread 'apple-eater :name "apple eater thread")))
309
+    (let ((grower-thread (sb-thread:make-thread 'apple-grower :name "apple grower thread")))
310
+      (sb-thread:join-thread eater-thread)))
311
+  (assert-equal (aref *orchard-log* 0) ____)
312
+  (assert-equal (aref *orchard-log* 1) ____))
313
+
314
+
315
+
316
+

+ 46 - 0
koans/triangle-project.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+"you need to write the triangle method"
17
+
18
+(define-condition triangle-error  (error) (()))
19
+
20
+(defun triangle (a b c)
21
+  :write-me)
22
+
23
+
24
+(define-test test-equilateral-triangles-have-equal-sides
25
+    (assert-equal :equilateral (triangle 2 2 2))
26
+    (assert-equal :equilateral (triangle 10 10 10)))
27
+
28
+
29
+(define-test test-isosceles-triangles-have-two-equal-sides
30
+    (assert-equal :isosceles (triangle 3 4 4))
31
+    (assert-equal :isosceles (triangle 4 3 4))
32
+    (assert-equal :isosceles (triangle 4 4 3))
33
+    (assert-equal :isosceles (triangle 10 10 2)))
34
+
35
+
36
+(define-test test-scalene-triangles-have-no-equal-sides
37
+    (assert-equal :scalene (triangle 3 4 5))
38
+    (assert-equal :scalene (triangle 10 11 12))
39
+    (assert-equal :scalene (triangle 5 4 2)))
40
+
41
+
42
+(define-test test-illegal-triangles-throw-exceptions
43
+    (assert-error 'triangle-error (triangle 0 0 0))
44
+    (assert-error 'triangle-error (triangle 3 4 -5))
45
+    (assert-error 'triangle-error (triangle 1 1 3))
46
+    (assert-error 'triangle-error (triangle 2 4 2)))

+ 120 - 0
koans/type-checking.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+;; Common lisp types have hierarchy.  Any object may belong a family of types.
16
+;; The top level type, which includes everything else, is 't'
17
+
18
+(define-test test-check-some-common-types
19
+   (true-or-false? ___  (typep "hello" 'string))
20
+   (true-or-false? ___  (typep "hello" 'array))
21
+   (true-or-false? ___  (typep "hello" 'list))
22
+   (true-or-false? ___  (typep "hello" '(simple-array character (5))))
23
+
24
+   (true-or-false? ___  (typep '(1 2 3) 'list))
25
+   (true-or-false? ___  (typep 99 'integer))
26
+   (true-or-false? ___  (typep nil 'NULL))
27
+   (true-or-false? ___  (typep 22/7 'ratio))
28
+   (true-or-false? ___  (typep 4.0 'float))
29
+   (true-or-false? ___  (typep #\a 'character))
30
+   (true-or-false? ___  (typep #'length 'function)))
31
+
32
+
33
+(define-test test-get-type-with-type-of
34
+   (assert-equal ____ (type-of ()))
35
+   (assert-equal ____ (type-of 4/6)))
36
+
37
+(define-test test-type-sets-may-overlap
38
+   (true-or-false? ___  (typep () 'list))
39
+   (true-or-false? ___  (typep () 'atom))
40
+   (true-or-false? ___  (typep () 'NULL))
41
+   (true-or-false? ___  (typep () t)))
42
+
43
+
44
+(define-test test-integers-can-get-really-big
45
+   (true-or-false? ____ (typep 12345678901234567890123456789012 'integer))
46
+   ;; Integers are either fixnum or bignum.
47
+   ;; The boundary between fixnum and bignum is given by the constant:
48
+   ;;   most-positive-fixnum
49
+   (assert-true (typep 1234567890123456789 'fixnum))
50
+   (assert-true (typep 12345678901234567890 'bignum))
51
+   (true-or-false? ___ (typep most-positive-fixnum 'fixnum))
52
+   (true-or-false? ___ (typep (+ 1 most-positive-fixnum) 'fixnum)))
53
+
54
+
55
+(define-test test-lisp-type-system-is-hierarchy
56
+   (assert-true (typep 1 'bit))
57
+   (assert-true (typep 1 'integer))
58
+   (assert-true (typep 2 'integer))
59
+   (true-or-false? ____ (subtypep 'bit 'integer))
60
+   (true-or-false? ____ (subtypep (type-of 1) (type-of 2)))
61
+   (true-or-false? ____ (subtypep (type-of 2) (type-of 1))))
62
+
63
+
64
+(define-test test-some-types-are-lists
65
+   (assert-true(typep (make-array 0 :element-type 'integer) '(SIMPLE-VECTOR 0)))
66
+   (true-or-false? ____ (typep (make-array '(3 3) :element-type 'integer) '(SIMPLE-ARRAY T (3 3)))))
67
+
68
+
69
+(define-test test-type-specifier-lists-also-have-hierarchy
70
+   (true-or-false? ____ (subtypep '(SIMPLE-ARRAY T (3 3)) '(SIMPLE-ARRAY T *)))
71
+   (true-or-false? ____ (subtypep '(vector double-float 100) '(vector * 100)))
72
+   (true-or-false? ____ (subtypep '(vector double-float 100) '(vector double-float *)))
73
+   (true-or-false? ____ (subtypep '(vector double-float 100) '(vector * *)))
74
+   (true-or-false? ____ (subtypep '(vector double-float 100) '(array number *)))
75
+   (true-or-false? ____ (subtypep '(vector double-float 100) t)))
76
+
77
+
78
+(define-test test-type-coersion
79
+   (assert-true (typep 0 'integer))
80
+   (true-or-false? ___ (typep 0 'short-float))
81
+   (true-or-false? ___ (subtypep 'integer 'short-float))
82
+   (true-or-false? ___ (subtypep 'short-float 'integer))
83
+   (true-or-false? ___ (typep (coerce 0 'short-float) 'short-float)))
84
+
85
+
86
+(define-test test-atoms-are-anything-thats-not-a-cons
87
+  (true-or-false? ___ (atom 4))
88
+  (true-or-false? ___ (atom '(1 2 3 4)))
89
+  (true-or-false? ___ (atom 'some-unbound-name))
90
+  (assert-true (typep (make-array '(4 4)) '(SIMPLE-ARRAY * *)))
91
+  (true-or-false? ___ (atom (make-array '(4 4)))))
92
+
93
+
94
+(define-test test-functionp
95
+    "the functionp predicate is true iff the argument is a function"
96
+  (assert-true (functionp (lambda (a b c) (+ a b c))))
97
+  (true-or-false? ___ (functionp #'make-array))
98
+  (true-or-false? ___ (functionp '(1 2 3)))
99
+  (true-or-false? ___ (functionp t)))
100
+
101
+
102
+(define-test test-there-are-some-other-type-predicates
103
+  ; see http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node73.html for more.
104
+  (true-or-false? ___ (numberp 999))
105
+  (true-or-false? ___ (listp '(9 9 9)))
106
+  (true-or-false? ___ (integerp 999))
107
+  (true-or-false? ___ (rationalp 9/99))
108
+  (true-or-false? ___ (floatp 9.99))
109
+  (true-or-false? ___ (stringp "nine nine nine"))
110
+  (true-or-false? ___ (characterp #\9))
111
+  (true-or-false? ___ (bit-vector-p #*01001)))
112
+
113
+
114
+(define-test test-guess-that-type!
115
+    (let ((x ____))
116
+      (assert-true (subtypep  x '(SIMPLE-ARRAY T (* 3 *))))
117
+      (assert-true (subtypep  x '(SIMPLE-ARRAY T (5 * *))))
118
+      (assert-true (subtypep  x '(SIMPLE-ARRAY ARRAY *)))
119
+      (assert-true (typep (make-array '(5 3 9) :element-type 'STRING ) x))
120
+      (assert-true (typep (make-array '(5 3 33) :element-type 'VECTOR ) x))))

+ 74 - 0
koans/variables-parameters-constants.lsp

1
+(defun test-variable-assignment-with-setf ()
2
+  ;; the let pattern allows us to create local variables with
3
+  ;; lexical scope.
4
+  (let (var_name_1 (var_name_2 "Michael"))
5
+  ;; variables may be defined with or without initial values.
6
+  (and
7
+   (equalp var_name_2 "Michael")
8
+   ; new values may be assigned to variables with setf
9
+   (setf var_name_2 "Janet")
10
+   (equalp var_name_2 "Janet")
11
+   ; setf may assign multiple variables in one form.
12
+   (setf var_name_1 "Tito"
13
+         var_name_2 "Jermaine")
14
+   (equalp var_name_1 "Tito")
15
+   (equalp var_name_2 "Jermaine"))))
16
+
17
+(defun test-setf-for-lists ()
18
+  ;; setf also works on list elements
19
+  (let (l)
20
+    (setf l '(1 2 3))
21
+    (equalp l '(1 2 3))
22
+    ; First second and third are convenient accessor functions
23
+    ; referring to the elements of a list
24
+    ; For those interested, they are convenient to car, cadr, and caddr
25
+    (setf (first l) 10)
26
+    (setf (second l) 20)
27
+    (setf (third l) 30)
28
+    (equalp l '(10 20 30))))
29
+
30
+(defparameter param_name_1 "Janet")
31
+; defparameter requires an initial form.  It is a compiler error to exclude it
32
+;(defparameter param_no_init)  ;; this will fail
33
+(defconstant additive_identity 0)
34
+; defconstant also requires an initial form
35
+; (defconstant constant_no_init)
36
+
37
+; reassigning parameters to new values is also ok, but parameters carry the
38
+; connotation of immutability.  If it's going to change frequently, it should
39
+; be a var.
40
+(setf param_name_1 "The other one")
41
+
42
+; reassigning a constant is an error.
43
+; this should result in a compile time error
44
+; (setf additive_identity -1)
45
+
46
+
47
+;; -------------------------------
48
+;; below is necessary to run tests.
49
+;; -------------------------------
50
+
51
+(defvar failed-test-names nil)
52
+
53
+(defun run-test (testfun)
54
+  (let ((fun-name (function-name testfun)))
55
+    (if (apply testfun '())
56
+        (format t ".")
57
+        (progn
58
+          (setf failed-test-names (cons fun-name failed-test-names))
59
+          (format t "F")))))
60
+
61
+(defun function-name (function) (nth-value 2 (function-lambda-expression function)))
62
+
63
+
64
+(run-test #'test-variable-assignment-with-setf)
65
+(run-test #'test-setf-for-lists)
66
+
67
+(format t "~%")
68
+
69
+(defun report-failure (test-name)
70
+  (format t "~S failed.~%" test-name))
71
+
72
+(if (endp failed-test-names)  ; no failed tests
73
+    (format t "all tests pass.~%")
74
+    (mapcar #'report-failure failed-test-names))

+ 50 - 0
koans/vectors.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+"vectors are just like rank 1 arrays"
16
+
17
+(define-test test-vector-types
18
+  " #(x y z) defines a vector literal containing x y z"
19
+  (true-or-false ___ (typep #(1 11 111) 'vector))
20
+  (assert-equal ___ (aref #(1 11 111) 1)))
21
+
22
+
23
+(define-test test-length-works-on-vectors
24
+  (assert-equal (length #(1 2 3)) ___ ))
25
+
26
+
27
+(define-test test-bit-vector
28
+    "#*0011 defines a bit vector literal with four elements, 0, 0, 1 and 1"
29
+  (assert-equal #*0011 (make-array '4 :element-type 'bit))
30
+  (true-or-false? ____ (typep #*1001 'bit-vector))
31
+  (assert-equal ____ (aref #*1001 1)))
32
+
33
+
34
+(define-test test-some-bitwise-operations
35
+    (assert-equal ___ (bit-and #*1100 #*1010))
36
+    (assert-equal ___ (bit-ior #*1100 #*1010))
37
+    (assert-equal ___ (bit-xor #*1100 #*1010)))
38
+
39
+
40
+(defun list-to-bit-vector (my-list)
41
+  nil)
42
+
43
+(define-test test-list-to-bit-vector
44
+    "you must complete list-to-bit-vector"
45
+  (assert-true (typep (list-to-bit-vector '(0 0 1 1 0)) 'bit-vector))
46
+  (assert-equal (aref (list-to-bit-vector '(0)) 0) 0)
47
+  (assert-equal (aref (list-to-bit-vector '(0 1)) 1) 1)
48
+  (assert-equal (length (list-to-bit-vector '(0 0 1 1 0 0 1 1))) 8))
49
+
50
+

+ 742 - 0
lisp-unit.lsp

1
+;;;-*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
2
+
3
+#|
4
+This version of lisp-unit.lsp has been extended to support the lisp koans.
5
+Specifically, it is an unnamed branch from
6
+https://github.com/OdonataResearchLLC/lisp-unit/
7
+with hash 93d07b2fa6e32364916225f6218e9e7313027c1f
8
+
9
+Modifications were made to:
10
+   1) Support *incomplete* tests in addition to *passing* and *failing* ones
11
+   2) End test execution at the first non-passing test.
12
+|#
13
+
14
+
15
+#|
16
+Copyright (c) 2004-2005 Christopher K. Riesbeck
17
+
18
+Permission is hereby granted, free of charge, to any person obtaining 
19
+a copy of this software and associated documentation files (the "Software"), 
20
+to deal in the Software without restriction, including without limitation 
21
+the rights to use, copy, modify, merge, publish, distribute, sublicense, 
22
+and/or sell copies of the Software, and to permit persons to whom the 
23
+Software is furnished to do so, subject to the following conditions:
24
+
25
+The above copyright notice and this permission notice shall be included 
26
+in all copies or substantial portions of the Software.
27
+
28
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
29
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
30
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
31
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
32
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
33
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
34
+OTHER DEALINGS IN THE SOFTWARE.
35
+
36
+
37
+How to use
38
+----------
39
+
40
+1. Read the documentation at:
41
+   https://github.com/OdonataResearchLLC/lisp-unit/wiki
42
+
43
+2. Make a file of DEFINE-TEST's. See exercise-tests.lisp for many
44
+examples. If you want, start your test file with (REMOVE-TESTS :ALL)
45
+to clear any previously defined tests.
46
+
47
+3. Load this file.
48
+
49
+4. (use-package :lisp-unit)
50
+
51
+5. Load your code file and your file of tests.
52
+
53
+6. Test your code with (RUN-TESTS '(test-name1 test-name2 ...)) or
54
+simply (RUN-TESTS :ALL) to run all defined tests.
55
+
56
+A summary of how many tests passed and failed will be printed.
57
+
58
+NOTE: Nothing is compiled until RUN-TESTS is expanded. Redefining
59
+functions or even macros does not require reloading any tests.
60
+
61
+|#
62
+
63
+#|
64
+   Copyright 2013 Google Inc.
65
+
66
+   Licensed under the Apache License, Version 2.0 (the "License");
67
+   you may not use this file except in compliance with the License.
68
+   You may obtain a copy of the License at
69
+
70
+       http://www.apache.org/licenses/LICENSE-2.0
71
+
72
+   Unless required by applicable law or agreed to in writing, software
73
+   distributed under the License is distributed on an "AS IS" BASIS,
74
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75
+   See the License for the specific language governing permissions and
76
+   limitations under the License.
77
+|#
78
+
79
+;;; Packages
80
+(in-package :cl-user)
81
+
82
+(defpackage :lisp-unit
83
+  (:use :common-lisp)
84
+  ;; Print parameters
85
+  (:export :*print-summary*
86
+           :*print-failures*
87
+           :*print-errors*
88
+           :*proceed-after-failure*)
89
+  ;; Forms for assertions
90
+  (:export :assert-eq
91
+           :assert-eql
92
+           :assert-equal
93
+           :true-or-false?
94
+           :assert-equalp
95
+           :assert-equality
96
+           :assert-prints
97
+           :assert-expands
98
+           :assert-true
99
+           :assert-false
100
+           :assert-error)
101
+  ;; Functions for managing tests
102
+  (:export :define-test
103
+           :list-tests
104
+           :test-code
105
+           :test-documentation
106
+           :remove-tests
107
+           :run-tests
108
+           :run-koans
109
+           :use-debugger)
110
+  ;; Functions for managing tags
111
+  (:export :list-tags
112
+           :tagged-tests
113
+           :remove-tags
114
+           :run-tags)
115
+  ;; Constants for blanks in koans
116
+  (:export __
117
+           ___
118
+           ____
119
+           +blanks+)
120
+  ;; Functions for reporting test results
121
+  (:export :test-names
122
+           :failed-tests
123
+           :incomplete-tests
124
+           :error-tests
125
+           :missing-tests
126
+           :summarize-results
127
+           :any-non-pass-p)
128
+  ;; Utility predicates
129
+  (:export :logically-equal :set-equal))
130
+
131
+(in-package :lisp-unit)
132
+
133
+
134
+;; blank constants allow the incomplete tests to compile without errors
135
+(defconstant __ :blank-value)
136
+(defconstant ___ :blank-value)
137
+(defconstant ____ :blank-value)
138
+(defconstant +blanks+ '(__ ___ ____))
139
+(defconstant +blank-value+ 'BLANK-VALUE)
140
+
141
+
142
+;;; Global counters
143
+
144
+(defparameter *pass* 0
145
+  "The number of passed assertions.")
146
+
147
+(defparameter *fail* 0
148
+  "The number of failed assertions.")
149
+
150
+(defparameter *incomplete* 0
151
+  "The number of incomplete assertions.")
152
+
153
+(defparameter *koan-assert-list* nil
154
+  "The record of a single koan.")
155
+
156
+;;; Global options
157
+
158
+(defparameter *proceed-after-failure* nil
159
+  "set to nil for normal operation.  t will eval every koan")
160
+
161
+(defparameter *print-summary* nil
162
+  "Print a summary of the pass, fail, and error count if non-nil.")
163
+
164
+(defparameter *print-failures* nil
165
+  "Print failure messages if non-NIL.")
166
+
167
+(defparameter *print-errors* nil
168
+  "Print error messages if non-NIL.")
169
+
170
+(defparameter *use-debugger* nil
171
+  "If not NIL, enter the debugger when an error is encountered in an
172
+assertion.")
173
+
174
+(defun use-debugger-p (condition)
175
+  "Debug or ignore errors."
176
+  (cond
177
+   ((eq :ask *use-debugger*)
178
+    (y-or-n-p "~A -- debug?" condition))
179
+   (*use-debugger*)))
180
+
181
+(defun use-debugger (&optional (flag t))
182
+  "Use the debugger when testing, or not."
183
+  (setq *use-debugger* flag))
184
+
185
+;;; Failure control strings
186
+
187
+(defgeneric print-failure (type form expected actual extras)
188
+  (:documentation
189
+   "Report the details of the failure assertion."))
190
+
191
+(defmethod print-failure :around (type form expected actual extras)
192
+  "Failure header and footer output."
193
+  (format t "~& | Failed Form: ~S" form)
194
+  (call-next-method)
195
+  (when extras
196
+    (format t "~{~& | ~S => ~S~}~%" (funcall extras)))
197
+  (format t "~& |~%")
198
+  type)
199
+
200
+(defmethod print-failure (type form expected actual extras)
201
+  (format t "~& | Expected ~{~S~^; ~} " expected)
202
+  (format t "~<~% | ~:;but saw ~{~S~^; ~}~>" actual))
203
+
204
+(defmethod print-failure ((type (eql :error))
205
+                          form expected actual extras)
206
+  (format t "~& | ~@[Should have signalled ~{~S~^; ~} but saw~]"
207
+          expected)
208
+  (format t " ~{~S~^; ~}" actual))
209
+
210
+(defmethod print-failure ((type (eql :macro))
211
+                          form expected actual extras)
212
+  (format t "~& | Should have expanded to ~{~S~^; ~} " expected)
213
+  (format t "~<~%~:;but saw ~{~S~^; ~}~>" actual))
214
+
215
+(defmethod print-failure ((type (eql :output))
216
+                          form expected actual extras)
217
+  (format t "~& | Should have printed ~{~S~^; ~} " expected)
218
+  (format t "~<~%~:;but saw ~{~S~^; ~}~>" actual))
219
+
220
+(defun print-error (condition)
221
+  "Print the error condition."
222
+  (let ((*print-escape* nil))
223
+    (format t "~& | Execution error:~% | ~W" condition)
224
+    (format t "~& |~%")))
225
+
226
+(defun print-summary (name pass fail incomplete &optional exerr)
227
+  "Print a summary of the test results."
228
+  (format t "~&~A: ~S assertions passed, ~S failed, ~S incomplete"
229
+          name pass fail incomplete)
230
+  (format t "~@[, ~S execution errors~].~2%" exerr))
231
+
232
+;;; Global unit test database
233
+
234
+(defparameter *test-db* (make-hash-table :test #'eq)
235
+  "The unit test database is simply a hash table.")
236
+
237
+(defun package-table (package &optional create)
238
+  (cond
239
+   ((gethash (find-package package) *test-db*))
240
+   (create
241
+    (setf (gethash package *test-db*) (make-hash-table)))
242
+   (t (warn "No tests defined for package: ~S" package))))
243
+
244
+;;; Global tags database
245
+
246
+(defparameter *tag-db* (make-hash-table :test #'eq)
247
+  "The tag database is simply a hash table.")
248
+
249
+(defun package-tags (package &optional create)
250
+  "Return the tags DB for the package."
251
+  (cond
252
+   ((gethash (find-package package) *tag-db*))
253
+   (create
254
+    (setf (gethash package *tag-db*) (make-hash-table)))
255
+   (t (warn "No tags defined for package: ~S" package))))
256
+
257
+(defclass unit-test ()
258
+  ((doc
259
+    :type string
260
+    :initarg :doc
261
+    :reader doc)
262
+   (code
263
+    :type list
264
+    :initarg :code
265
+    :reader code))
266
+  (:default-initargs :doc "" :code ())
267
+  (:documentation
268
+   "Organize the unit test documentation and code."))
269
+
270
+;;; NOTE: Shamelessly taken from PG's analyze-body
271
+(defun parse-body (body &optional doc tag)
272
+  "Separate the components of the body."
273
+  (let ((item (first body)))
274
+    (cond
275
+     ((and (listp item) (eq :tag (first item)))
276
+      (parse-body (rest body) doc (nconc (rest item) tag)))
277
+     ((and (stringp item) (not doc) (rest body))
278
+      (if tag
279
+          (values doc tag (rest body))
280
+          (parse-body (rest body) doc tag)))
281
+     (t (values doc tag body)))))
282
+
283
+(defmacro define-test (name &body body)
284
+  "Store the test in the test database."
285
+  (multiple-value-bind (doc tag code) (parse-body body)
286
+    `(let ((doc (or ,doc (string ',name))))
287
+       (setf
288
+        ;; Unit test
289
+        (gethash ',name (package-table *package* t))
290
+        (make-instance 'unit-test :doc doc :code ',code))
291
+       ;; Tags
292
+       (loop for tag in ',tag do
293
+             (pushnew
294
+              ',name (gethash tag (package-tags *package* t))))
295
+       ;; Return the name of the test
296
+       ',name)))
297
+
298
+;;; Manage tests
299
+
300
+(defun list-tests (&optional (package *package*))
301
+  "Return a list of the tests in package."
302
+  (let ((table (package-table package)))
303
+    (when table
304
+      (loop for test-name being each hash-key in table
305
+            collect test-name))))
306
+
307
+(defun test-documentation (name &optional (package *package*))
308
+  "Return the documentation for the test."
309
+  (let ((unit-test (gethash name (package-table package))))
310
+    (if (null unit-test)
311
+        (warn "No code defined for test ~A in package ~S."
312
+              name package)
313
+        (doc unit-test))))
314
+
315
+(defun test-code (name &optional (package *package*))
316
+  "Returns the code stored for the test name."
317
+  (let ((unit-test (gethash name (package-table package))))
318
+    (if (null unit-test)
319
+        (warn "No code defined for test ~A in package ~S."
320
+              name package)
321
+        (code unit-test))))
322
+
323
+(defun remove-tests (names &optional (package *package*))
324
+  "Remove individual tests or entire sets."
325
+  (if (eq :all names)
326
+      (if (null package)
327
+          (clrhash *test-db*)
328
+          (progn
329
+            (remhash (find-package package) *test-db*)
330
+            (remhash (find-package package) *tag-db*)))
331
+      (let ((table (package-table package)))
332
+        (unless (null table)
333
+          ;; Remove tests
334
+          (loop for name in names
335
+                always (remhash name table)
336
+                collect name into removed
337
+                finally (return removed))
338
+          ;; Remove tests from tags
339
+          (loop with tags = (package-tags package)
340
+                for tag being each hash-key in tags
341
+                using (hash-value tagged-tests)
342
+                do
343
+                (setf
344
+                 (gethash tag tags)
345
+                 (set-difference tagged-tests names)))))))
346
+
347
+;;; Manage tags
348
+
349
+(defun %tests-from-all-tags (&optional (package *package*))
350
+  "Return all of the tests that have been tagged."
351
+  (loop for tests being each hash-value in (package-tags package)
352
+        nconc (copy-list tests) into all-tests
353
+        finally (return (delete-duplicates all-tests))))
354
+
355
+(defun %tests-from-tags (tags &optional (package *package*))
356
+  "Return the tests associated with the tags."
357
+  (loop with table = (package-tags package)
358
+        for tag in tags
359
+        as tests = (gethash tag table)
360
+        nconc (copy-list tests) into all-tests
361
+        finally (return (delete-duplicates all-tests))))
362
+
363
+(defun list-tags (&optional (package *package*))
364
+  "Return a list of the tags in package."
365
+  (let ((tags (package-tags package)))
366
+    (when tags
367
+      (loop for tag being each hash-key in tags collect tag))))
368
+
369
+(defun tagged-tests (tags &optional (package *package*))
370
+  "Run the tests associated with the specified tags in package."
371
+  (if (eq :all tags)
372
+      (%tests-from-all-tags package)
373
+      (%tests-from-tags tags package)))
374
+
375
+(defun remove-tags (tags &optional (package *package*))
376
+  "Remove individual tags or entire sets."
377
+  (if (eq :all tags)
378
+      (if (null package)
379
+          (clrhash *tag-db*)
380
+          (remhash (find-package package) *tag-db*))
381
+      (let ((table (package-tags package)))
382
+        (unless (null table)
383
+          (loop for tag in tags
384
+                always (remhash tag table)
385
+                collect tag into removed
386
+                finally (return removed))))))
387
+
388
+;;; Assert macros
389
+
390
+(defmacro assert-eq (expected form &rest extras)
391
+  "Assert whether expected and form are EQ."
392
+  `(expand-assert :equal ,form ,form ,expected ,extras :test #'eq))
393
+
394
+(defmacro assert-eql (expected form &rest extras)
395
+  "Assert whether expected and form are EQL."
396
+  `(expand-assert :equal ,form ,form ,expected ,extras :test #'eql))
397
+
398
+(defmacro assert-equal (expected form &rest extras)
399
+  "Assert whether expected and form are EQUAL."
400
+  `(expand-assert :equal ,form ,form ,expected ,extras :test #'equal))
401
+
402
+(defmacro assert-equalp (expected form &rest extras)
403
+  "Assert whether expected and form are EQUALP."
404
+  `(expand-assert :equal ,form ,form ,expected ,extras :test #'equalp))
405
+
406
+(defmacro true-or-false? (expected form &rest extras)
407
+  "Assert whether expected and form are EQUAL."
408
+  `(expand-assert :equal ,form (not (not ,form)) ,expected ,extras :test #'equal))
409
+
410
+(defmacro assert-error (condition form &rest extras)
411
+  "Assert whether form signals condition."
412
+  `(expand-assert :error ,form (expand-error-form ,form)
413
+                  ,condition ,extras))
414
+
415
+(defmacro assert-expands (expansion form &rest extras)
416
+  "Assert whether form expands to expansion."
417
+  `(expand-assert :macro ,form
418
+                  (expand-macro-form ,form nil)
419
+                  ,expansion ,extras))
420
+
421
+(defmacro assert-false (form &rest extras)
422
+  "Assert whether the form is false."
423
+  `(expand-assert :result ,form ,form nil ,extras))
424
+
425
+(defmacro assert-equality (test expected form &rest extras)
426
+  "Assert whether expected and form are equal according to test."
427
+  `(expand-assert :equal ,form ,form ,expected ,extras :test ,test))
428
+
429
+(defmacro assert-prints (output form &rest extras)
430
+  "Assert whether printing the form generates the output."
431
+  `(expand-assert :output ,form (expand-output-form ,form)
432
+                  ,output ,extras))
433
+
434
+(defmacro assert-true (form &rest extras)
435
+  "Assert whether the form is true."
436
+  `(expand-assert :result ,form ,form t ,extras))
437
+
438
+(defmacro expand-assert (type form body expected extras &key (test '#'eql))
439
+  "Expand the assertion to the internal format."
440
+  `(internal-assert ,type ',form
441
+                    (lambda () ,body)
442
+                    (lambda () ,expected)
443
+                    (expand-extras ,extras)
444
+                    ,test))
445
+
446
+(defmacro expand-error-form (form)
447
+  "Wrap the error assertion in HANDLER-CASE."
448
+  `(handler-case ,form
449
+     (condition (error) error)))
450
+
451
+(defmacro expand-output-form (form)
452
+  "Capture the output of the form in a string."
453
+  (let ((out (gensym)))
454
+    `(let* ((,out (make-string-output-stream))
455
+            (*standard-output*
456
+             (make-broadcast-stream *standard-output* ,out)))
457
+       ,form
458
+       (get-output-stream-string ,out))))
459
+
460
+(defmacro expand-macro-form (form env)
461
+  "Expand the macro form once."
462
+  `(macroexpand-1 ',form ,env))
463
+
464
+(defmacro expand-extras (extras)
465
+  "Expand extra forms."
466
+  `(lambda ()
467
+     (list ,@(mapcan (lambda (form) (list `',form form)) extras))))
468
+
469
+;;; Test passed predicate.
470
+
471
+(defgeneric test-passed-p (type expected actual test)
472
+  (:documentation
473
+   "Return the result of the test."))
474
+
475
+(defmethod test-passed-p ((type (eql :error)) expected actual test)
476
+  "Return the result of the error assertion."
477
+  (or
478
+   (eql (car actual) (car expected))
479
+   (typep (car actual) (car expected))))
480
+
481
+(defmethod test-passed-p ((type (eql :equal)) expected actual test)
482
+  "Return the result of the equality assertion."
483
+  (and
484
+   (<= (length expected) (length actual))
485
+   (every test expected actual)))
486
+
487
+(defmethod test-passed-p ((type (eql :macro)) expected actual test)
488
+  "Return the result of the macro expansion."
489
+  (equal (car actual) (car expected)))
490
+
491
+(defmethod test-passed-p ((type (eql :output)) expected actual test)
492
+  "Return the result of the printed output."
493
+  (string=
494
+   (string-trim '(#\newline #\return #\space) (car actual))
495
+   (car expected)))
496
+
497
+;;; (LOGICALLY-EQUAL x y) => true or false
498
+;;;   Return true if x and y both false or both true
499
+(defun logically-equal (x y)
500
+  (eql (not x) (not y)))
501
+
502
+(defmethod test-passed-p ((type (eql :result)) expected actual test)
503
+  "Return the result of the assertion."
504
+  (logically-equal (car actual) (car expected)))
505
+
506
+(defun form-contains-one-of-p (form symbol-list)
507
+  ;; returns nil if form contains (recursively) no element of the symbol-list
508
+  ;; otherwise it returns the first element of symbol-list that it finds
509
+  ;; in form.
510
+  (cond
511
+    ((symbolp form) (find form symbol-list))
512
+    ((listp form) (or (form-contains-one-of-p (car form) symbol-list)
513
+                      (form-contains-one-of-p (cdr form) symbol-list)))
514
+    (t nil)))
515
+
516
+(defun internal-assert
517
+       (type form code-thunk expected-thunk extras test)  
518
+  "Perform the assertion and record the results."
519
+  (let* ((expected (multiple-value-list (funcall expected-thunk)))
520
+         (actual (multiple-value-list (funcall code-thunk)))
521
+         (passed (test-passed-p type expected actual test))
522
+         (incomplete (or (form-contains-one-of-p form +blanks+)
523
+                         (form-contains-one-of-p expected '(:blank-value)))))
524
+
525
+   (cond
526
+      (incomplete (progn
527
+                    (incf *incomplete*)
528
+                    (push :incomplete *koan-assert-list*)))
529
+      (passed (progn
530
+                (incf *pass*)
531
+                (push :pass *koan-assert-list*)))
532
+      (t (progn
533
+           (incf *fail*)
534
+           (push :fail *koan-assert-list*))))
535
+    ;; Report the assertion
536
+    (when (and (not passed) *print-failures*)
537
+      (print-failure type form expected actual extras))
538
+    ;; Return the result
539
+    passed))
540
+
541
+;;; results
542
+
543
+(defclass test-results ()
544
+  ((test-names
545
+    :type list
546
+    :initarg :test-names
547
+    :accessor test-names)
548
+   (pass
549
+    :type fixnum
550
+    :initform 0
551
+    :accessor pass)
552
+   (fail
553
+    :type fixnum
554
+    :initform 0
555
+    :accessor fail)
556
+   (incomplete
557
+    :type fixnum
558
+    :initform 0
559
+    :accessor incomplete)
560
+   (exerr
561
+    :type fixnum
562
+    :initform 0
563
+    :accessor exerr)
564
+   (failed-tests
565
+    :type list
566
+    :initform ()
567
+    :accessor failed-tests)
568
+   (incomplete-tests
569
+    :type list
570
+    :initform ()
571
+    :accessor incomplete-tests)
572
+   (error-tests
573
+    :type list
574
+    :initform ()
575
+    :accessor error-tests)
576
+   (missing-tests
577
+    :type list
578
+    :initform ()
579
+    :accessor missing-tests))
580
+  (:default-initargs :test-names ())
581
+  (:documentation
582
+   "Store the results of the tests for further evaluation."))
583
+
584
+(defmethod print-object ((object test-results) stream)
585
+  "Print the summary counts with the object."
586
+  (format stream "#<~A Total(~D) Passed(~D) Failed(~D) Incomplete(~D) Errors(~D)>~%"
587
+          (class-name (class-of object))
588
+          (+ (pass object) (fail object) (incomplete object))
589
+          (pass object) (fail object) (incomplete object) (exerr object)))
590
+
591
+(defun summarize-results (results)
592
+  "Print a summary of all results."
593
+  (let ((pass (pass results))
594
+        (fail (fail results))
595
+        (incomplete (incomplete results)))
596
+    (format t "~&Unit Test Summary~%")
597
+    (format t " | ~D assertions total~%" (+ pass fail incomplete))
598
+    (format t " | ~D passed~%" pass)
599
+    (format t " | ~D failed~%" fail)
600
+    (format t " | ~D incomplete~%" incomplete)
601
+    (format t " | ~D execution errors~%" (exerr results))
602
+    (format t " | ~D missing tests~2%"
603
+            (length (missing-tests results)))))
604
+
605
+;;; Run the tests
606
+
607
+(defun run-code (code)
608
+  "Run the code to test the assertions."
609
+  (funcall (coerce `(lambda () ,@code) 'function)))
610
+
611
+(defun run-test-thunk (code)
612
+  (let ((*pass* 0)
613
+        (*fail* 0)
614
+        (*incomplete* 0))
615
+    (handler-bind
616
+        ((error (lambda (condition)
617
+                  (when *print-errors*
618
+                    (print-error condition))
619
+                  (if (use-debugger-p condition)
620
+                      condition
621
+                      (return-from run-test-thunk
622
+                        (values *pass* *fail* *incomplete* condition))))))
623
+      (run-code code))
624
+    ;; Return the result count
625
+    (values *pass* *fail* *incomplete* nil)))
626
+
627
+(defun run-koan-thunk (code)
628
+  (let ((*koan-assert-list* nil))
629
+    (handler-bind
630
+        ((error (lambda (condition)
631
+                  (push :error *koan-assert-list*)
632
+                  (when *print-errors*
633
+                    (print-error condition))
634
+                  (if (use-debugger-p condition)
635
+                      condition
636
+                      (return-from run-koan-thunk
637
+                        (values *koan-assert-list* condition))))))
638
+      (run-code code))
639
+    ;; Return the result count
640
+    (values *koan-assert-list* nil)))
641
+
642
+(defun koan-result (code)
643
+   "Run the code.  Return a list of assertion result elements.
644
+    An assertion result element is one of :pass, :fail, :error, :incomplete"
645
+   (run-koan-thunk code))
646
+
647
+(defun record-result (test-name code results)
648
+  "Run the test code and record the result."
649
+  (multiple-value-bind (pass fail incomplete exerr)
650
+      (run-test-thunk code)
651
+    (push test-name (test-names results))
652
+    ;; Count passed tests
653
+    (when (plusp pass)
654
+      (incf (pass results) pass))
655
+    ;; Count failed tests and record name
656
+    (when (plusp fail)
657
+      (incf (fail results) fail)
658
+      (push test-name (failed-tests results)))
659
+    ;; Count incomplete tests and record name
660
+    (when (plusp incomplete)
661
+      (incf (incomplete results) incomplete)
662
+      (push test-name (incomplete-tests results)))
663
+    ;; Count errors and record name
664
+    (when exerr
665
+      (incf (exerr results))
666
+      (push test-name (error-tests results)))
667
+    ;; Print a summary of the results
668
+    (when (or *print-summary* *print-failures* *print-errors*)
669
+      (print-summary
670
+       test-name pass fail incomplete (when exerr 1)))))
671
+
672
+(defun %run-all-thunks (&optional (package *package*))
673
+  "Run all of the test thunks in the package."
674
+  (loop
675
+   with results = (make-instance 'test-results)
676
+   for test-name being each hash-key in (package-table package)
677
+   using (hash-value unit-test)
678
+   if unit-test do
679
+   (record-result test-name (code unit-test) results)
680
+   else do
681
+   (push test-name (missing-tests results))
682
+   ;; Summarize and return the test results
683
+   finally
684
+   (summarize-results results)
685
+   (return results)))
686
+
687
+(defun %run-thunks (test-names &optional (package *package*))
688
+  "Run the list of test thunks in the package."
689
+  (loop
690
+   with table = (package-table package)
691
+   and results = (make-instance 'test-results)
692
+   for test-name in test-names
693
+   as unit-test = (gethash test-name table)
694
+   if unit-test do
695
+   (record-result test-name (code unit-test) results)
696
+   else do
697
+   (push test-name (missing-tests results))
698
+   finally
699
+   (summarize-results results)
700
+   (return results)))
701
+
702
+(defun run-koans (package)
703
+  "Run the list of test thunks in the package. Stopping
704
+   at a failure or incomplete, with more helpful messaging"
705
+  (loop
706
+    with koan-results = nil
707
+    for test-name being each hash-key in (package-table package)
708
+    using (hash-value unit-test)
709
+    if unit-test do
710
+      (push (list test-name (koan-result (code unit-test))) koan-results)
711
+    else do
712
+      (push (list test-name :missing) koan-results)
713
+    until (and (not *proceed-after-failure*) (any-non-pass-p koan-results))
714
+    finally (return koan-results)))
715
+
716
+(defun any-non-pass-p (koan-results)
717
+  (dolist (one-koan koan-results)
718
+    (dolist (assert-result (second one-koan))
719
+      (if (not (equal :pass assert-result))
720
+          (return-from any-non-pass-p t))))
721
+  nil)
722
+
723
+(defun run-tests (test-names &optional (package *package*))
724
+  "Run the specified tests in package."
725
+  (if (eq :all test-names)
726
+      (%run-all-thunks package)
727
+      (%run-thunks test-names package)))
728
+
729
+(defun run-tags (tags &optional (package *package*))
730
+  "Run the tests associated with the specified tags in package."
731
+  (%run-thunks (tagged-tests tags package) package))
732
+
733
+;;; (SET-EQUAL l1 l2 :test) => true or false
734
+;;;   Return true if every element of l1 is an element of l2
735
+;;;   and vice versa.
736
+(defun set-equal (l1 l2 &key (test #'equal))
737
+  (and (listp l1)
738
+       (listp l2)
739
+       (subsetp l1 l2 :test test)
740
+       (subsetp l2 l1 :test test)))
741
+
742
+(pushnew :lisp-unit common-lisp:*features*)

+ 35 - 0
unused-test-ideas.lsp

1
+;;   Copyright 2013 Google Inc.
2
+;;
3
+;;   Licensed under the Apache License, Version 2.0 (the "License");
4
+;;   you may not use this file except in compliance with the License.
5
+;;   You may obtain a copy of the License at
6
+;;
7
+;;       http://www.apache.org/licenses/LICENSE-2.0
8
+;;
9
+;;   Unless required by applicable law or agreed to in writing, software
10
+;;   distributed under the License is distributed on an "AS IS" BASIS,
11
+;;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+;;   See the License for the specific language governing permissions and
13
+;;   limitations under the License.
14
+
15
+
16
+; todo: add the nconc example somewhere and take care of the warning.
17
+
18
+'(define-test test-nconc
19
+    "nconc like append attaches one list to the end of the other, but
20
+     it does so in a more efficient, but potentially destructive way.
21
+     Lisp lists are nil terminated.  A symbol refers to the beginning of
22
+     a list, and then progresses to find the end.  'nconc' simply takes
23
+     the nil pointer at the end of the first list, and points it at the
24
+     beginning of the next list."
25
+  (assert-equal '(:a :b :c) (nconc '(:a :b) '(:c))) ;k
26
+
27
+  (let ((abc '(:a :b :c))
28
+        (xyz '(:x :y :z))
29
+        (abcxyz nil))
30
+    (setf abcxyz (nconc abc xyz))
31
+    (assert-equal '(:a :b :c :x :y :z) abcxyz)
32
+    (assert-equal '(:a :b :c :x :y :z) abc)
33
+    (assert-equal '(:x :y :z) xyz)))
34
+
35
+