diff --git a/koans-solved/backquote.lisp b/koans-solved/backquote.lisp index d8e15fdb..e1a187d3 100644 --- a/koans-solved/backquote.lisp +++ b/koans-solved/backquote.lisp @@ -19,23 +19,25 @@ (let ((x '(123)) (z '(7 8 9))) ;; ' quotes an expression normally. - (assert-equal ____ '(x 45 6 z)) + (assert-equal '(x 45 6 z) '(x 45 6 z)) ;; ` backquotes an expression; without any unquotes, it is equivalent to ;; using the normal quote. - (assert-equal ____ `(x 45 6 z)) + (assert-equal '(x 45 6 z) `(x 45 6 z)) ;; , unquotes a part of the expression. - (assert-equal ____ `(,x 45 6 z)) - (assert-equal ____ `(,x 45 6 ,z)) + (assert-equal '((123) 45 6 z) `(,x 45 6 z)) + (assert-equal '((123) 45 6 (7 8 9)) `(,x 45 6 ,z)) ;; ,@ splices an expression into the into the list surrounding it. - (assert-equal ____ `(,x 45 6 ,@z)) - (assert-equal ____ `(,@x 45 6 ,@z)))) + (assert-equal '((123) 45 6 7 8 9) `(,x 45 6 ,@z)) + (assert-equal '(123 45 6 7 8 9) `(,@x 45 6 ,@z)))) (define-test backquote-forms ;; Because of its properties, backquote is useful for constructing Lisp forms ;; that are macroexpansions or parts of macroexpansions. (let ((variable 'x)) ;; Fill in the blank without without using backquote/unquote notation. - (assert-equal ____ + (assert-equal '(if (typep x 'string) + (format nil "The value of ~A is ~A" 'x x) + (error 'type-error :datum x :expected-type 'string)) `(if (typep ,variable 'string) (format nil "The value of ~A is ~A" ',variable ,variable) (error 'type-error :datum ,variable @@ -43,7 +45,9 @@ (let ((error-type 'type-error) (error-arguments '(:datum x :expected-type 'string))) ;; Fill in the blank without without using backquote/unquote notation. - (assert-equal ____ + (assert-equal '(if (typep x 'string) + (format nil "The value of ~A is ~A" 'x x) + (error 'type-error :datum x :expected-type 'string)) `(if (typep x 'string) (format nil "The value of ~A is ~A" 'x x) (error ',error-type ,@error-arguments))))) @@ -51,15 +55,17 @@ (define-test numbers-and-words (let ((number 5) (word 'dolphin)) - (true-or-false? ____ (equal '(1 3 5) `(1 3 5))) - (true-or-false? ____ (equal '(1 3 5) `(1 3 number))) - (assert-equal _____ `(1 3 ,number)) - (assert-equal _____ `(word ,word ,word word)))) + (true-or-false? t (equal '(1 3 5) `(1 3 5))) + (true-or-false? nil (equal '(1 3 5) `(1 3 number))) + (assert-equal '(1 3 5) `(1 3 ,number)) + (assert-equal '(word dolphin dolphin word) `(word ,word ,word word)))) (define-test splicing (let ((axis '(x y z))) - (assert-equal '(the axis are ____) `(the axis are ,axis)) - (assert-equal '(the axis are ____) `(the axis are ,@axis))) + (assert-equal '(the axis are (x y z)) `(the axis are ,axis)) + (assert-equal '(the axis are x y z) `(the axis are ,@axis))) (let ((coordinates '((43.15 77.6) (42.36 71.06)))) - (assert-equal ____ `(the coordinates are ,coordinates)) - (assert-equal ____ `(the coordinates are ,@coordinates)))) + (assert-equal '(the coordinates are ((43.15 77.6) (42.36 71.06))) + `(the coordinates are ,coordinates)) + (assert-equal '(the coordinates are (43.15 77.6) (42.36 71.06)) + `(the coordinates are ,@coordinates)))) diff --git a/koans-solved/condition-handlers.lisp b/koans-solved/condition-handlers.lisp index 24ae56a1..5ccb085d 100644 --- a/koans-solved/condition-handlers.lisp +++ b/koans-solved/condition-handlers.lisp @@ -37,25 +37,25 @@ (define-test type-hierarchy ;; Inheritance for condition types works the same way as for classes. (let ((condition (make-condition 'my-condition))) - (true-or-false? ____ (typep condition 'my-condition)) - (true-or-false? ____ (typep condition 'condition)) - (true-or-false? ____ (typep condition 'warning)) - (true-or-false? ____ (typep condition 'error))) + (true-or-false? t (typep condition 'my-condition)) + (true-or-false? t (typep condition 'condition)) + (true-or-false? nil (typep condition 'warning)) + (true-or-false? nil (typep condition 'error))) (let ((condition (make-condition 'my-warning))) - (true-or-false? ____ (typep condition 'my-warning)) - (true-or-false? ____ (typep condition 'warning)) - (true-or-false? ____ (typep condition 'error))) + (true-or-false? t (typep condition 'my-warning)) + (true-or-false? t (typep condition 'warning)) + (true-or-false? nil (typep condition 'error))) (let ((condition (make-condition 'my-serious-condition))) - (true-or-false? ____ (typep condition 'my-serious-condition)) - (true-or-false? ____ (typep condition 'serious-condition)) - (true-or-false? ____ (typep condition 'warning)) - (true-or-false? ____ (typep condition 'error))) + (true-or-false? t (typep condition 'my-serious-condition)) + (true-or-false? t (typep condition 'serious-condition)) + (true-or-false? nil (typep condition 'warning)) + (true-or-false? nil (typep condition 'error))) (let ((condition (make-condition 'my-error))) - (true-or-false? ____ (typep condition 'my-error)) - (true-or-false? ____ (typep condition 'my-serious-condition)) - (true-or-false? ____ (typep condition 'serious-condition)) - (true-or-false? ____ (typep condition 'warning)) - (true-or-false? ____ (typep condition 'error)))) + (true-or-false? t (typep condition 'my-error)) + (true-or-false? nil (typep condition 'my-serious-condition)) + (true-or-false? t (typep condition 'serious-condition)) + (true-or-false? nil (typep condition 'warning)) + (true-or-false? t (typep condition 'error)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -64,88 +64,104 @@ (defvar *list*) -(defun handle-my-error (condition) +(define-condition foo () ()) + +(define-condition bar (foo) ()) + +(define-condition baz (bar) ()) + +(defun handle-foo (condition) (declare (ignore condition)) - (push :my-error *list*)) + (push :foo *list*)) -(defun handle-error (condition) +(defun handle-bar (condition) (declare (ignore condition)) - (push :error *list*)) + (push :bar *list*)) -(defun handle-my-serious-condition (condition) +(defun handle-baz (condition) (declare (ignore condition)) - (push :my-serious-condition *list*)) + (push :baz *list*)) (define-test handler-bind ;; When a condition is signaled, all handlers whose type matches the ;; condition's type are allowed to execute. (let ((*list* '())) - (handler-bind ((my-error #'handle-my-error) - (error #'handle-error) - (my-serious-condition #'handle-my-serious-condition)) - (signal (make-condition 'my-error))) - (assert-equal ____ *list*))) + (handler-bind ((bar #'handle-bar) + (foo #'handle-foo) + (baz #'handle-baz)) + (signal (make-condition 'baz))) + (assert-equal '(:baz :foo :bar) *list*))) (define-test handler-order ;; The order of binding handlers matters. (let ((*list* '())) - (handler-bind ((error #'handle-error) - (my-error #'handle-my-error) - (my-serious-condition #'handle-my-serious-condition)) - (signal (make-condition 'my-error))) - (assert-equal ____ *list*))) + (handler-bind ((foo #'handle-foo) + (bar #'handle-bar) + (baz #'handle-baz)) + (signal (make-condition 'baz))) + (assert-equal '(:baz :bar :foo) *list*))) (define-test multiple-handler-binds ;; It is possible to bind handlers in steps. (let ((*list* '())) - (handler-bind ((error #'handle-error) - (my-serious-condition #'handle-my-serious-condition)) - (handler-bind ((my-error #'handle-my-error)) - (signal (make-condition 'my-error)))) - (assert-equal ____ *list*))) + (handler-bind ((foo #'handle-foo) + (baz #'handle-baz)) + (handler-bind ((bar #'handle-bar)) + (signal (make-condition 'baz)))) + (assert-equal '(:baz :foo :bar) *list*))) (define-test same-handler ;; The same handler may be bound multiple times. (let ((*list* '())) - (handler-bind ((error #'handle-error) - (error #'handle-error)) - (handler-bind ((my-error #'handle-my-error) - (error #'handle-error) - (my-error #'handle-my-error)) - (signal (make-condition 'my-error)))) - (assert-equal ____ *list*))) + (handler-bind ((foo #'handle-foo) + (foo #'handle-foo)) + (handler-bind ((bar #'handle-bar) + (foo #'handle-foo) + (bar #'handle-bar)) + (signal (make-condition 'baz)))) + (assert-equal '(:foo :foo :bar :foo :bar) *list*))) (define-test handler-types ;; A handler is not executed if it does not match the condition type. (let ((*list* '())) - (handler-bind ((error #'handle-error) - (my-error #'handle-my-error) - (my-serious-condition #'handle-my-serious-condition)) - (signal (make-condition 'my-serious-condition))) - (assert-equal ____ *list*))) + (handler-bind ((foo #'handle-foo) + (bar #'handle-bar) + (baz #'handle-baz)) + (signal (make-condition 'bar))) + (assert-equal '(:bar :foo) *list*))) (define-test handler-transfer-of-control ;; A handler may decline to handle the condition if it returns normally, ;; or it may handle the condition by transferring control elsewhere. (let ((*list* '())) (block my-block - (handler-bind ((error #'handle-error) - (error (lambda (condition) - (declare (ignore condition)) - (return-from my-block))) - (error #'handle-error)) - (signal (make-condition 'my-error)))) - (assert-equal ____ *list*))) + (handler-bind ((foo #'handle-foo) + (foo (lambda (condition) + (declare (ignore condition)) + (return-from my-block))) + (foo #'handle-foo)) + (signal (make-condition 'foo)))) + (assert-equal '(:foo) *list*))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun handle-error (condition) + (declare (ignore condition)) + (push :error *list*)) + +(define-condition my-error (error) ()) + +(defun handle-my-error (condition) + (declare (ignore condition)) + (push :my-error *list*)) + (define-test handler-case ;; HANDLER-CASE always transfers control before executing the case forms. (let ((*list* '())) (handler-case (signal (make-condition 'my-error)) (error (condition) (handle-error condition)) (my-error (condition) (handle-my-error condition))) - (assert-equal ____ *list*))) + (assert-equal '(:error) *list*))) (define-test handler-case-order ;; The order of handler cases matters. @@ -153,7 +169,7 @@ (handler-case (signal (make-condition 'my-error)) (my-error (condition) (handle-my-error condition)) (error (condition) (handle-error condition))) - (assert-equal ____ *list*))) + (assert-equal '(:my-error) *list*))) (define-test handler-case-type ;; A handler cases is not executed if it does not match the condition type. @@ -161,7 +177,7 @@ (handler-case (signal (make-condition 'error)) (my-error (condition) (handle-my-error condition)) (error (condition) (handle-error condition))) - (assert-equal ____ *list*))) + (assert-equal '(:error) *list*))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -172,8 +188,8 @@ ;; ASSERT-ERROR is a Lisp Koans macro which verifies that the correct error ;; type is signaled. (assert-equal 3 (divide 6 2)) - (assert-error 'division-by-zero (divide 6 0)) - (assert-error 'type-error (divide 6 :zero))) + (assert-error (divide 6 0) 'division-by-zero) + (assert-error (divide 6 :zero) 'type-error)) (define-test error-signaling-handler-case (flet ((try-to-divide (numerator denominator) @@ -181,9 +197,9 @@ (handler-case (divide numerator denominator) (division-by-zero () :division-by-zero) (type-error () :type-error)))) - (assert-equal ____ (try-to-divide 6 2)) - (assert-equal ____ (try-to-divide 6 0)) - (assert-equal ____ (try-to-divide 6 :zero)))) + (assert-equal 3 (try-to-divide 6 2)) + (assert-equal :division-by-zero (try-to-divide 6 0)) + (assert-equal :type-error (try-to-divide 6 :zero)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -192,18 +208,18 @@ (define-test accessors-division-by-zero (let ((condition (handler-case (divide 6 0) (division-by-zero (c) c)))) - (assert-equal ____ (arithmetic-error-operands condition)) + (assert-equal '(6 0) (arithmetic-error-operands condition)) (let ((operation (arithmetic-error-operation condition))) - (assert-equal ____ (funcall operation 12 4))))) + (assert-equal 3 (funcall operation 12 4))))) (define-test accessors-type-error (let ((condition (handler-case (divide 6 :zero) (type-error (c) c)))) - (assert-equal ____ (type-error-datum condition)) + (assert-equal :zero (type-error-datum condition)) (let ((expected-type (type-error-expected-type condition))) - (true-or-false? ____ (typep :zero expected-type)) - (true-or-false? ____ (typep 0 expected-type)) - (true-or-false? ____ (typep "zero" expected-type)) - (true-or-false? ____ (typep 0.0 expected-type))))) + (true-or-false? nil (typep :zero expected-type)) + (true-or-false? t (typep 0 expected-type)) + (true-or-false? nil (typep "zero" expected-type)) + (true-or-false? t (typep 0.0 expected-type))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -218,9 +234,9 @@ ;; The macro CHECK-TYPE signals a TYPE-ERROR if the object is not of the ;; specified type. (check-type line string) - (cond ((= 0 (search "TIMESTAMP" line)) :timestamp) - ((= 0 (search "HTTP" line)) :http) - ((= 0 (search "LOGIN" line)) :login) + (cond ((eql 0 (search "TIMESTAMP" line)) :timestamp) + ((eql 0 (search "HTTP" line)) :http) + ((eql 0 (search "LOGIN" line)) :login) ;; The function ERROR should be used for signaling serious conditions ;; and errors: if the condition is not handled, it halts program ;; execution and starts the Lisp debugger. @@ -231,12 +247,12 @@ (flet ((try-log-line-type (line) (handler-case (log-line-type line) (error (condition) condition)))) - (assert-equal ____ (try-log-line-type "TIMESTAMP 2020-05-08 16:59:39")) - (assert-equal ____ (try-log-line-type "HTTP GET / from 127.0.0.1")) - (assert-equal ____ (try-log-line-type "LOGIN administrator:hunter2")) + (assert-equal :timestamp (try-log-line-type "TIMESTAMP 2020-05-08 16:59:39")) + (assert-equal :http (try-log-line-type "HTTP GET / from 127.0.0.1")) + (assert-equal :login (try-log-line-type "LOGIN administrator:hunter2")) (let ((condition (try-log-line-type "WARNING: 95% of disk space used"))) - (assert-equal ____ (line condition)) - (assert-equal ____ (reason condition))) + (assert-equal "WARNING: 95% of disk space used" (line condition)) + (assert-equal :unknown-log-line-type (reason condition))) (let ((condition (try-log-line-type 5555))) - (assert-equal 'string (____ condition)) - (assert-equal 5555 (____ condition))))) + (assert-equal 'string (type-error-expected-type condition)) + (assert-equal 5555 (type-error-datum condition))))) diff --git a/koans-solved/dice-project.lisp b/koans-solved/dice-project.lisp index e9a4a3d6..bc26513b 100644 --- a/koans-solved/dice-project.lisp +++ b/koans-solved/dice-project.lisp @@ -18,17 +18,22 @@ (defclass dice-set () ;; Fill in the blank with a proper slot definition. - (____)) + ((values :accessor dice-values :initform '()))) -(defmethod dice-values ((object dice-set)) - ____) +;;; This method might be unnecessary, depending on how you define the slots of +;;; DICE-SET. + +;; (defmethod dice-values ((object dice-set)) +;; ____) (defmethod roll ((count integer) (object dice-set)) - ____) + (check-type count (integer 1)) + (setf (dice-values object) + (loop repeat count collect (random 6)))) (define-test make-dice-set (let ((dice (make-instance 'dice-set))) - (assert-true (type-of dice 'dice-set)))) + (assert-true (typep dice 'dice-set)))) (define-test dice-are-six-sided (let ((dice (make-instance 'dice-set))) @@ -80,12 +85,12 @@ (let* ((condition (dice-failure value)) (expected-type (type-error-expected-type condition))) (assert-true (typep condition 'type-error)) - (assert-equal value (type-error-datum)) + (assert-equal value (type-error-datum condition)) (assert-true (subtypep expected-type '(integer 1 6))) (assert-true (subtypep '(integer 1 6) expected-type))))) - (test-dice-failure 0) - (test-dice-failure "0") - (test-dice-failure :zero) - (test-dice-failure 18.0) - (test-dice-failure -7) - (test-dice-failure '(6 6 6))))) + (dice-failure 0) + (dice-failure "0") + (dice-failure :zero) + (dice-failure 18.0) + (dice-failure -7) + (dice-failure '(6 6 6))))) diff --git a/koans-solved/extra-credit.lisp b/koans-solved/extra-credit.lisp index 0e4be3f4..4e51c5dc 100644 --- a/koans-solved/extra-credit.lisp +++ b/koans-solved/extra-credit.lisp @@ -1,3 +1,17 @@ +;;; Copyright 2013 Google Inc. +;;; +;;; Licensed under the Apache License, Version 2.0 (the "License"); +;;; you may not use this file except in compliance with the License. +;;; You may obtain a copy of the License at +;;; +;;; http://www.apache.org/licenses/LICENSE-2.0 +;;; +;;; Unless required by applicable law or agreed to in writing, software +;;; distributed under the License is distributed on an "AS IS" BASIS, +;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;;; See the License for the specific language governing permissions and +;;; limitations under the License. + ;;; EXTRA CREDIT: ;;; ;;; Create a program that will play the Greed game. @@ -7,3 +21,7 @@ ;;; Write a PLAYER class and a GAME class to complete the project. ;;; ;;; This is a free form assignment, so approach it however you desire. + +(define-test play-greed + ;; This page intentionally left blank. + (assert-true t)) diff --git a/koans-solved/macros.lisp b/koans-solved/macros.lisp index f4f9e607..74a7c707 100644 --- a/koans-solved/macros.lisp +++ b/koans-solved/macros.lisp @@ -30,12 +30,15 @@ ;; ASSERT-EXPANDS macroexpands the first form once and checks if it is equal ;; to the second form. (assert-expands (my-and (= 0 (random 6)) (error "Bang!")) - (when (= 0 (random 6)) (error "Bang!"))) + '(when (= 0 (random 6)) (error "Bang!"))) (assert-expands (my-and (= 0 (random 6)) (= 0 (random 6)) (= 0 (random 6)) (error "Bang!")) - ____)) + '(when (= 0 (random 6)) + (when (= 0 (random 6)) + (when (= 0 (random 6)) + (error "Bang!")))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -50,9 +53,9 @@ (let ((limit 10) (result '())) (for (i 0 3) - (push i result) - (assert-equal ____ limit)) - (assert-equal ____ (nreverse result))))) + (push i result) + (assert-equal 3 limit)) + (assert-equal '(0 1 2 3) (nreverse result))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -71,9 +74,9 @@ (flet ((return-0 () (push 0 side-effects) 0) (return-3 () (push 3 side-effects) 3)) (for (i (return-0) (return-3)) - (push i result))) - (assert-equal ____ (nreverse result)) - (assert-equal ____ (nreverse side-effects))))) + (push i result))) + (assert-equal '(0 1 2 3) (nreverse result)) + (assert-equal '(0 3 3 3 3 3) (nreverse side-effects))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -95,9 +98,9 @@ (flet ((return-0 () (push 0 side-effects) 0) (return-3 () (push 3 side-effects) 3)) (for (i (return-0) (return-3)) - (push i result))) - (assert-equal ____ (nreverse result)) - (assert-equal ____ (nreverse side-effects))))) + (push i result))) + (assert-equal '(0 1 2 3) (nreverse result)) + (assert-equal '(3 0) (nreverse side-effects))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -105,12 +108,16 @@ (macrolet ((for ((var start stop) &body body) ;; Fill in the blank with a correct FOR macroexpansion that is ;; not affected by the three macro pitfalls mentioned above. - ____)) + (let ((limit (gensym "LIMIT"))) + `(do ((,var ,start (1+ ,var)) + (,limit ,stop)) + ((> ,var ,limit)) + ,@body)))) (let ((side-effects '()) (result '())) (flet ((return-0 () (push 0 side-effects) 0) (return-3 () (push 3 side-effects) 3)) (for (i (return-0) (return-3)) - (push i result))) + (push i result))) (assert-equal '(0 1 2 3) (nreverse result)) (assert-equal '(0 3) (nreverse side-effects))))) diff --git a/koans-solved/std-method-comb.lisp b/koans-solved/std-method-comb.lisp index f456d35d..6553c8be 100644 --- a/koans-solved/std-method-comb.lisp +++ b/koans-solved/std-method-comb.lisp @@ -13,7 +13,7 @@ ;;; limitations under the License. (defclass access-counter () - ((value :reader value :initform :value) + ((value :accessor value :initarg :value) (access-count :reader access-count :initform 0))) ;;; The generated reader, writer, and accessor functions are generic functions. @@ -27,23 +27,23 @@ (defmethod value :after ((object access-counter)) (incf (slot-value object 'access-count))) -(defmethod (setf value) :after ((object access-counter)) +(defmethod (setf value) :after (new-value (object access-counter)) (incf (slot-value object 'access-count))) (define-test defmethod-after (let ((counter (make-instance 'access-counter :value 42))) - (assert-equal ____ (access-count counter)) - (assert-equal ____ (value counter)) - (assert-equal ____ (access-count counter)) + (assert-equal 0 (access-count counter)) + (assert-equal 42 (value counter)) + (assert-equal 1 (access-count counter)) (setf (value counter) 24) - (assert-equal ____ (access-count counter)) - (assert-equal ____ (value counter)) - (assert-equal ____ (access-count counter)) + (assert-equal 2 (access-count counter)) + (assert-equal 24 (value counter)) + (assert-equal 3 (access-count counter)) ;; We read the value three more times and discard the result. (value counter) (value counter) (value counter) - (assert-equal ____ (access-count counter)))) + (assert-equal 6 (access-count counter)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -61,9 +61,9 @@ (:method (was-nice-p) (declare (ignore was-nice-p)) :lollipop)) (define-test lollipop - (assert-equal ____ (grab-lollipop)) - (assert-equal ____ (grab-lollipop-while-mom-is-nearby t)) - (assert-equal ____ (grab-lollipop-while-mom-is-nearby nil))) + (assert-equal :lollipop (grab-lollipop)) + (assert-equal :lollipop (grab-lollipop-while-mom-is-nearby t)) + (assert-equal :no-lollipop (grab-lollipop-while-mom-is-nearby nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -72,21 +72,22 @@ ;; REMAINING-TIME function is called, it should return a number one less than ;; the previous time that it returned. If the countdown hits zero, :BANG ;; should be returned instead. - ((remaining-time :reader remaining-time :initarg :value))) + ((remaining-time :reader remaining-time :initarg :time))) (defmethod remaining-time :around ((object countdown)) - (let ((value (call-next-method))) - (if (<= 0 value) + (let ((time (call-next-method))) + (if (< 0 time) ;; DECF is similar to INCF. It decreases the value stored in the place ;; and returns the decreased value. - (decf value) + (decf (slot-value object 'remaining-time)) :bang))) (define-test countdown - (let ((countdown (make-instance 'countdown :value 4))) + (let ((countdown (make-instance 'countdown :time 4))) (assert-equal 3 (remaining-time countdown)) (assert-equal 2 (remaining-time countdown)) (assert-equal 1 (remaining-time countdown)) + (assert-equal 0 (remaining-time countdown)) (assert-equal :bang (remaining-time countdown)) (assert-equal :bang (remaining-time countdown)))) @@ -124,10 +125,10 @@ (define-test multiple-methods (let ((object (make-instance 'object))) (frobnicate object) - (assert-equal ____ (counter object))) + (assert-equal 2305070 (counter object))) (let ((object (make-instance 'bigger-object))) (frobnicate object) - (assert-equal ____ (counter object)))) + (assert-equal 12345678 (counter object)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -161,10 +162,10 @@ (define-test standard-method-combination-order (let ((object (make-instance 'object))) (calculate object) - (assert-equal ____ (counter object))) + (assert-equal -1/94 (counter object))) (let ((object (make-instance 'bigger-object))) (calculate object) - (assert-equal ____ (counter object)))) + (assert-equal 197/99 (counter object)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -190,13 +191,13 @@ (define-test salary-at-company-a (let ((programmer (make-instance 'programmer))) - (assert-equal ____ (salary-at-company-a programmer))) + (assert-equal 120000 (salary-at-company-a programmer))) (let ((programmer (make-instance 'senior-programmer))) - (assert-equal ____ (salary-at-company-a programmer))) + (assert-equal 320000 (salary-at-company-a programmer))) (let ((programmer (make-instance 'full-stack-programmer))) - (assert-equal ____ (salary-at-company-a programmer))) + (assert-equal 168000 (salary-at-company-a programmer))) (let ((programmer (make-instance 'senior-full-stack-programmer))) - (assert-equal ____ (salary-at-company-a programmer)))) + (assert-equal 368000 (salary-at-company-a programmer)))) ;;; It is also possible to define custom method combinations. @@ -210,10 +211,10 @@ (define-test salary-at-company-b (let ((programmer (make-instance 'programmer))) - (assert-equal ____ (salary-at-company-b programmer))) + (assert-equal 120000 (salary-at-company-b programmer))) (let ((programmer (make-instance 'senior-programmer))) - (assert-equal ____ (salary-at-company-b programmer))) + (assert-equal 240000 (salary-at-company-b programmer))) (let ((programmer (make-instance 'full-stack-programmer))) - (assert-equal ____ (salary-at-company-b programmer))) + (assert-equal 168000 (salary-at-company-b programmer))) (let ((programmer (make-instance 'senior-full-stack-programmer))) - (assert-equal ____ (salary-at-company-b programmer)))) + (assert-equal 336000 (salary-at-company-b programmer)))) diff --git a/koans-solved/triangle-project.lisp b/koans-solved/triangle-project.lisp index 2eec4805..a5a6ea34 100644 --- a/koans-solved/triangle-project.lisp +++ b/koans-solved/triangle-project.lisp @@ -14,11 +14,20 @@ (define-condition triangle-error (error) ;; Fill in the blank with a suitable slot definition. - (____)) + ((triangle-error-sides :reader triangle-error-sides :initarg :sides))) (defun triangle (a b c) - ;;;Fill in the blank with a function that satisfies the below tests. - ____) + (check-type a (real (0))) + (check-type b (real (0))) + (check-type c (real (0))) + ;; Fill in the blank with a function that satisfies the below tests. + (let* ((min (min a b c)) + (max (max a b c)) + (mid (car (remove min (remove max (list a b c) :count 1) :count 1)))) + (cond ((<= (+ min mid) max) (error 'triangle-error :sides (list a b c))) + ((= max mid min) :equilateral) + ((= max mid) :isosceles) + (t :scalene)))) (define-test equilateral-triangles ;; Equilateral triangles have three sides of equal length, @@ -45,7 +54,7 @@ (error (condition) condition)))) (let ((condition (triangle-failure 0 0 0))) (assert-true (typep condition 'type-error)) - (assert-equal 0 (type-error-datum)) + (assert-equal 0 (type-error-datum condition)) ;; The type (REAL (0)) represents all positive numbers. (assert-true (subtypep (type-error-expected-type condition) '(real (0)))) ;; If two type specifiers are SUBTYPEP of one another, then they represent @@ -53,7 +62,7 @@ (assert-true (subtypep '(real (0)) (type-error-expected-type condition)))) (let ((condition (triangle-failure 3 4 -5))) (assert-true (typep condition 'type-error)) - (assert-equal -5 (type-error-datum)) + (assert-equal -5 (type-error-datum condition)) (assert-true (subtypep (type-error-expected-type condition) '(real (0)))) (assert-true (subtypep '(real (0)) (type-error-expected-type condition)))) (let ((condition (triangle-failure 1 1 3))) diff --git a/koans/backquote.lisp b/koans/backquote.lisp index d8e15fdb..c66deba1 100644 --- a/koans/backquote.lisp +++ b/koans/backquote.lisp @@ -53,7 +53,7 @@ (word 'dolphin)) (true-or-false? ____ (equal '(1 3 5) `(1 3 5))) (true-or-false? ____ (equal '(1 3 5) `(1 3 number))) - (assert-equal _____ `(1 3 ,number)) + (assert-equal ____ `(1 3 ,number)) (assert-equal _____ `(word ,word ,word word)))) (define-test splicing diff --git a/koans/condition-handlers.lisp b/koans/condition-handlers.lisp index 24ae56a1..7bac4bfb 100644 --- a/koans/condition-handlers.lisp +++ b/koans/condition-handlers.lisp @@ -172,8 +172,8 @@ ;; ASSERT-ERROR is a Lisp Koans macro which verifies that the correct error ;; type is signaled. (assert-equal 3 (divide 6 2)) - (assert-error 'division-by-zero (divide 6 0)) - (assert-error 'type-error (divide 6 :zero))) + (assert-error (divide 6 0) 'division-by-zero) + (assert-error (divide 6 :zero) 'type-error)) (define-test error-signaling-handler-case (flet ((try-to-divide (numerator denominator) @@ -218,9 +218,9 @@ ;; The macro CHECK-TYPE signals a TYPE-ERROR if the object is not of the ;; specified type. (check-type line string) - (cond ((= 0 (search "TIMESTAMP" line)) :timestamp) - ((= 0 (search "HTTP" line)) :http) - ((= 0 (search "LOGIN" line)) :login) + (cond ((eql 0 (search "TIMESTAMP" line)) :timestamp) + ((eql 0 (search "HTTP" line)) :http) + ((eql 0 (search "LOGIN" line)) :login) ;; The function ERROR should be used for signaling serious conditions ;; and errors: if the condition is not handled, it halts program ;; execution and starts the Lisp debugger. diff --git a/koans/dice-project.lisp b/koans/dice-project.lisp index e9a4a3d6..ea6e7b0c 100644 --- a/koans/dice-project.lisp +++ b/koans/dice-project.lisp @@ -20,6 +20,9 @@ ;; Fill in the blank with a proper slot definition. (____)) +;;; This method might be unnecessary, depending on how you define the slots of +;;; DICE-SET. + (defmethod dice-values ((object dice-set)) ____) @@ -28,7 +31,7 @@ (define-test make-dice-set (let ((dice (make-instance 'dice-set))) - (assert-true (type-of dice 'dice-set)))) + (assert-true (typep dice 'dice-set)))) (define-test dice-are-six-sided (let ((dice (make-instance 'dice-set))) @@ -80,12 +83,12 @@ (let* ((condition (dice-failure value)) (expected-type (type-error-expected-type condition))) (assert-true (typep condition 'type-error)) - (assert-equal value (type-error-datum)) + (assert-equal value (type-error-datum condition)) (assert-true (subtypep expected-type '(integer 1 6))) (assert-true (subtypep '(integer 1 6) expected-type))))) - (test-dice-failure 0) - (test-dice-failure "0") - (test-dice-failure :zero) - (test-dice-failure 18.0) - (test-dice-failure -7) - (test-dice-failure '(6 6 6))))) + (dice-failure 0) + (dice-failure "0") + (dice-failure :zero) + (dice-failure 18.0) + (dice-failure -7) + (dice-failure '(6 6 6))))) diff --git a/koans/extra-credit.lisp b/koans/extra-credit.lisp index 0e4be3f4..2bd62be9 100644 --- a/koans/extra-credit.lisp +++ b/koans/extra-credit.lisp @@ -1,3 +1,17 @@ +;;; Copyright 2013 Google Inc. +;;; +;;; Licensed under the Apache License, Version 2.0 (the "License"); +;;; you may not use this file except in compliance with the License. +;;; You may obtain a copy of the License at +;;; +;;; http://www.apache.org/licenses/LICENSE-2.0 +;;; +;;; Unless required by applicable law or agreed to in writing, software +;;; distributed under the License is distributed on an "AS IS" BASIS, +;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;;; See the License for the specific language governing permissions and +;;; limitations under the License. + ;;; EXTRA CREDIT: ;;; ;;; Create a program that will play the Greed game. @@ -7,3 +21,6 @@ ;;; Write a PLAYER class and a GAME class to complete the project. ;;; ;;; This is a free form assignment, so approach it however you desire. + +(define-test play-greed + (assert-true ____)) diff --git a/koans/macros.lisp b/koans/macros.lisp index f4f9e607..85415138 100644 --- a/koans/macros.lisp +++ b/koans/macros.lisp @@ -30,7 +30,7 @@ ;; ASSERT-EXPANDS macroexpands the first form once and checks if it is equal ;; to the second form. (assert-expands (my-and (= 0 (random 6)) (error "Bang!")) - (when (= 0 (random 6)) (error "Bang!"))) + '(when (= 0 (random 6)) (error "Bang!"))) (assert-expands (my-and (= 0 (random 6)) (= 0 (random 6)) (= 0 (random 6)) @@ -50,8 +50,8 @@ (let ((limit 10) (result '())) (for (i 0 3) - (push i result) - (assert-equal ____ limit)) + (push i result) + (assert-equal ____ limit)) (assert-equal ____ (nreverse result))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/koans/std-method-comb.lisp b/koans/std-method-comb.lisp index f456d35d..661c51e5 100644 --- a/koans/std-method-comb.lisp +++ b/koans/std-method-comb.lisp @@ -13,7 +13,7 @@ ;;; limitations under the License. (defclass access-counter () - ((value :reader value :initform :value) + ((value :accessor value :initarg :value) (access-count :reader access-count :initform 0))) ;;; The generated reader, writer, and accessor functions are generic functions. @@ -27,7 +27,7 @@ (defmethod value :after ((object access-counter)) (incf (slot-value object 'access-count))) -(defmethod (setf value) :after ((object access-counter)) +(defmethod (setf value) :after (new-value (object access-counter)) (incf (slot-value object 'access-count))) (define-test defmethod-after @@ -72,23 +72,24 @@ ;; REMAINING-TIME function is called, it should return a number one less than ;; the previous time that it returned. If the countdown hits zero, :BANG ;; should be returned instead. - ((remaining-time :reader remaining-time :initarg :value))) + ((remaining-time :reader remaining-time :initarg :time))) (defmethod remaining-time :around ((object countdown)) - (let ((value (call-next-method))) - (if (<= 0 value) + (let ((time (call-next-method))) + (if (< 0 time) ;; DECF is similar to INCF. It decreases the value stored in the place ;; and returns the decreased value. - (decf value) + (decf (slot-value object 'remaining-time)) :bang))) (define-test countdown - (let ((countdown (make-instance 'countdown :value 4))) + (let ((countdown (make-instance 'countdown :time 4))) (assert-equal 3 (remaining-time countdown)) - (assert-equal 2 (remaining-time countdown)) - (assert-equal 1 (remaining-time countdown)) - (assert-equal :bang (remaining-time countdown)) - (assert-equal :bang (remaining-time countdown)))) + (assert-equal ____ (remaining-time countdown)) + (assert-equal ____ (remaining-time countdown)) + (assert-equal ____ (remaining-time countdown)) + (assert-equal ____ (remaining-time countdown)) + (assert-equal ____ (remaining-time countdown)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/koans/triangle-project.lisp b/koans/triangle-project.lisp index 2eec4805..275f0340 100644 --- a/koans/triangle-project.lisp +++ b/koans/triangle-project.lisp @@ -17,7 +17,7 @@ (____)) (defun triangle (a b c) - ;;;Fill in the blank with a function that satisfies the below tests. + ;; Fill in the blank with a function that satisfies the below tests. ____) (define-test equilateral-triangles @@ -45,7 +45,7 @@ (error (condition) condition)))) (let ((condition (triangle-failure 0 0 0))) (assert-true (typep condition 'type-error)) - (assert-equal 0 (type-error-datum)) + (assert-equal 0 (type-error-datum condition)) ;; The type (REAL (0)) represents all positive numbers. (assert-true (subtypep (type-error-expected-type condition) '(real (0)))) ;; If two type specifiers are SUBTYPEP of one another, then they represent @@ -53,7 +53,7 @@ (assert-true (subtypep '(real (0)) (type-error-expected-type condition)))) (let ((condition (triangle-failure 3 4 -5))) (assert-true (typep condition 'type-error)) - (assert-equal -5 (type-error-datum)) + (assert-equal -5 (type-error-datum condition)) (assert-true (subtypep (type-error-expected-type condition) '(real (0)))) (assert-true (subtypep '(real (0)) (type-error-expected-type condition)))) (let ((condition (triangle-failure 1 1 3))) diff --git a/lisp-koans.lisp b/lisp-koans.lisp index 58224003..39d15271 100644 --- a/lisp-koans.lisp +++ b/lisp-koans.lisp @@ -102,13 +102,14 @@ (koan-status-message koan-status) dirname filename koan-name koan-status))) (defun print-completion-message () - (format t "********************************************************* + (format t " +********************************************************* That was the last one, well done! ENLIGHTENMENT IS YOURS! ********************************************************* If you demand greater challenge, take a look at extra-credit.lisp Or, let the student become the teacher: -Write and submit your own improvements to https://github.com/google/lisp-koans! +Write and submit your own improvements to https://github.com/google/lisp-koans!~% ")) (defun print-progress-message () diff --git a/test-framework.lisp b/test-framework.lisp index 2540a6ea..7952132a 100644 --- a/test-framework.lisp +++ b/test-framework.lisp @@ -142,11 +142,13 @@ (defmacro assert-error (form condition) "Assert whether form signals condition." - `(expand-assert :error ,form (handler-case ,form (error (e) e)) ,condition)) + (let ((e (gensym "E"))) + `(expand-assert :error ,form (handler-case ,form (error (,e) (type-of ,e))) + ,condition))) (defmacro assert-expands (form expected) "Assert whether form expands to expansion." - `(expand-assert :macro ',form (macroexpand-1 ',form) ',expected)) + `(expand-assert :macro ',form (macroexpand-1 ',form) ,expected)) (defmacro assert-false (form) "Assert whether the form is false."