diff --git a/koans/arrays.lisp b/koans/arrays.lisp index c00c17fa..7b2912e3 100644 --- a/koans/arrays.lisp +++ b/koans/arrays.lisp @@ -14,28 +14,29 @@ ;;; See http://www.gigamonkeys.com/book/collections.html -(define-test test-basic-array-stuff - "We define an 8x8 array and then fill it with a checkerboard pattern." +(define-test basic-array-stuff + ;; We make an 8x8 array and then fill it with a checkerboard pattern. (let ((chess-board (make-array '(8 8)))) - "(DOTIMES (X 8) ...) will iterate with X taking values from 0 to 7." + ;; (DOTIMES (X 8) ...) will iterate with X taking values from 0 to 7. (dotimes (x 8) (dotimes (y 8) - "AREF stands for \"array reference\"." + ;; AREF stands for "array reference". (setf (aref chess-board x y) (if (evenp (+ x y)) :black :white)))) (assert-true (typep chess-board 'array)) - (assert-equal (aref chess-board 0 0) ____) - (assert-equal (aref chess-board 2 3) ____) - "ARRAY-RANK returns the number of dimensions of the array." + (assert-equal ____ (aref chess-board 0 0)) + (assert-equal ____ (aref chess-board 2 3)) + ;; The function ARRAY-RANK returns the number of dimensions of the array. (assert-equal ____ (array-rank chess-board)) - "ARRAY-DIMENSIONS returns a list of the cardinality of the array dims" + ;; The function ARRAY-DIMENSIONS returns a list of the cardinality of the + ;; array dimensions. (assert-equal ____ (array-dimensions chess-board)) - "ARRAY-TOTAL-SIZE returns the total number of elements in the array." + ;; ARRAY-TOTAL-SIZE returns the total number of elements in the array. (assert-equal ____ (array-total-size chess-board)))) -(define-test test-make-your-own-array - "Make your own array that meets the specifications below." +(define-test make-your-own-array + ;; Make your own array that satisfies the test. (let ((color-cube ____)) - "You may need to modify your array after you create it." + ;; You may need to modify your array after you create it. (setf (____ color-cube ____ ____ ____) ____ (____ color-cube ____ ____ ____) ____) (if (typep color-cube '(simple-array T (3 3 3))) @@ -47,25 +48,25 @@ (assert-equal (aref color-cube 2 1 0) :white)) (assert-true nil)))) -(define-test test-adjustable-array - "The size of an array does not need to be constant." +(define-test adjustable-array + ;; The size of an array does not need to be constant. (let ((x (make-array '(2 2) :initial-element 5 :adjustable t))) - (assert-equal (aref x 1 0) ____) - (assert-equal (array-dimensions x) ____) + (assert-equal ____ (aref x 1 0)) + (assert-equal ____ (array-dimensions x)) (adjust-array x '(3 4)) - (assert-equal (array-dimensions x) ____))) + (assert-equal ____ (array-dimensions x)))) -(define-test test-make-array-from-list - "One can create arrays from list structure." +(define-test make-array-from-list + ;; One can create arrays with initial contents. (let ((x (make-array '(4) :initial-contents '(:one :two :three :four)))) - (assert-equal (array-dimensions x) ____) + (assert-equal ____ (array-dimensions x)) (assert-equal ____ (aref x 0)))) -(define-test test-row-major-index - "Row major indexing is a way to access elements with a single integer, - rather than a list of integers." +(define-test row-major-index + ;; Row major indexing is a way to access elements with a single integer, + ;; rather than a list of integers. (let ((my-array (make-array '(2 2 2 2)))) (dotimes (i (* 2 2 2 2)) (setf (row-major-aref my-array i) i)) - (assert-equal (aref my-array 0 0 0 0) ____) - (assert-equal (aref my-array 1 1 1 1) ____))) + (assert-equal ____ (aref my-array 0 0 0 0)) + (assert-equal ____ (aref my-array 1 1 1 1)))) diff --git a/koans/basic-macros.lisp b/koans/basic-macros.lisp index dc1d8dd0..28412c7f 100644 --- a/koans/basic-macros.lisp +++ b/koans/basic-macros.lisp @@ -66,21 +66,20 @@ (assert-equal :found-a-nil (case-special-symbols-match nil)) (assert-equal :something-else (case-special-symbols-match 42))) -(defun cartoon-dads (input) - (case input - ;; Fill in the blanks with proper cases. - ____ - ____ - ____ - (:this-one-doesnt-happen :fancy-cat) - (t :unknown))) - (define-test your-own-case-statement - ;; You need to fill in the blanks in CARTOON-DADS. - (assert-equal (cartoon-dads :bart) :homer) - (assert-equal (cartoon-dads :stewie) :peter) - (assert-equal (cartoon-dads :stan) :randy) - (assert-equal (cartoon-dads :space-ghost) :unknown)) + ;; We use FLET to define a local function. + (flet ((cartoon-dads (input) + (case input + ;; Fill in the blanks with proper cases. + ____ + ____ + ____ + (:this-one-doesnt-happen :fancy-cat) + (t :unknown)))) + (assert-equal (cartoon-dads :bart) :homer) + (assert-equal (cartoon-dads :stewie) :peter) + (assert-equal (cartoon-dads :stan) :randy) + (assert-equal (cartoon-dads :space-ghost) :unknown))) (define-test limits-of-case ;; So far, we have been comparing objects using EQUAL, one of the Lisp diff --git a/koans/equality-distinctions.lisp b/koans/equality-distinctions.lisp index 50e0b55a..4bfb72af 100644 --- a/koans/equality-distinctions.lisp +++ b/koans/equality-distinctions.lisp @@ -1,92 +1,121 @@ -;; 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. +;;; 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. -;; the most common equality predicates are eq, eql, equal and equalp -;; eq is similar to comparing c pointers -(define-test test-eq - "(eq x y) is true if and only if x and y are the same identical object - eq is like comparing pointers in c. If the values are EQ, any non-nil - value may be returned." - (true-or-false? ___ (eq 'a 'a)) - (true-or-false? ___ (eq 3 3.0)) - (true-or-false? ___ (eq '(1 2) '(1 2))) - (true-or-false? ___ (eq "Foo" "Foo")) - (true-or-false? ___ (eq "Foo" (copy-seq "Foo"))) - (true-or-false? ___ (eq "FOO" "Foo"))) +;;; The most common equality predicates in Common Lisp are, in order of +;;; strictness, EQ, EQL, EQUAL, and EQUALP. -(define-test test-eql - "(eql x y) is true if (eq x y) - also it is true if x and y are numeric of the same type - and represent the same number. - (eql x y) also if x and y are the same characters." - (true-or-false? ___ (eql 'a 'a)) - (true-or-false? ___ (eql 3 3)) - (true-or-false? ___ (eql 3 3.0)) - (true-or-false? ___ (eql '(1 2) '(1 2))) - (true-or-false? ___ (eql '(:a . :b) '(:a . :b))) - (true-or-false? ___ (eql #\S #\S)) - (true-or-false? ___ (eql "Foo" "Foo")) - (true-or-false? ___ (eql "Foo" (copy-seq "Foo"))) - (true-or-false? ___ (eql "FOO" "Foo"))) +(define-test eq + ;; EQ checks the identity of the two objects; it checks whether the two + ;; objects are, in fact, one and the same object. + ;; It is the fastest of the four; however, not guaranteed to work on numbers + ;; and characters because of that. + (true-or-false? ____ (eq 'a 'a)) + (true-or-false? ____ (eq 3 3.0)) + (true-or-false? ____ (eq '(1 2) '(1 2))) + (true-or-false? ____ (eq "Foo" "Foo")) + (true-or-false? ____ (eq "Foo" (copy-seq "Foo"))) + (true-or-false? ____ (eq "FOO" "Foo"))) -(define-test test-equal - "(equal x y) is true if (eql x y), or - x and y are lists with equal elements, or - x and y character or bit arrays with equal elements" - (true-or-false? ___ (equal 'a 'a)) - (true-or-false? ___ (equal 3 3)) - (true-or-false? ___ (equal 3 3.0)) - (true-or-false? ___ (equal '(1 2) '(1 2))) - (true-or-false? ___ (equal '(:a . :b) '(:a . :b))) - (true-or-false? ___ (equal '(:a . :b) '(:a . :doesnt-match))) - (true-or-false? ___ (equal #\S #\S)) - (true-or-false? ___ (equal "Foo" "Foo")) - (true-or-false? ___ (equal "Foo" (copy-seq "Foo"))) - (true-or-false? ___ (equal "FOO" "Foo"))) +(define-test eql + ;; EQL works like EQ, except it is specified to work for numbers and + ;; characters. + ;; Two numbers are EQL if they are of the same type and represent the same + ;; number. Two characters are EQL if they represent the same character. + (true-or-false? ____ (eql 'a 'a)) + (true-or-false? ____ (eql 3 3)) + (true-or-false? ____ (eql 3 3.0)) + (true-or-false? ____ (eql '(1 2) '(1 2))) + (true-or-false? ____ (eql '(:a . :b) '(:a . :b))) + (true-or-false? ____ (eql #\S #\S)) + (true-or-false? ____ (eql "Foo" "Foo")) + (true-or-false? ____ (eql "Foo" (copy-seq "Foo"))) + (true-or-false? ____ (eql "FOO" "Foo"))) -(define-test test-equalp - "(equalp x y) if (equal x y) or - if x and y are strings with the same characters (case independent). - if x and y are arrays with the same dimensions and equal elements - if x and y are numeric of different types but one may be upgraded to - the other type without loss and still exhibit equality." - (true-or-false? ___ (equalp 'a 'a)) - (true-or-false? ___ (equalp 3 3)) - (true-or-false? ___ (equalp 3 3.0)) - (true-or-false? ___ (equalp '(1 2) '(1 2))) - (true-or-false? ___ (equalp '(:a . :b) '(:a . :b))) - (true-or-false? ___ (equalp '(:a . :b) '(:a . :doesnt-match))) - (true-or-false? ___ (equalp #\S #\S)) - (true-or-false? ___ (equalp "Foo" "Foo")) - (true-or-false? ___ (equalp "Foo" (copy-seq "Foo"))) - (true-or-false? ___ (equalp "FOO" "Foo"))) +(define-test equal + ;; EQUAL works like EQL, except works differently for lists, strings, bit + ;; vectors, and pathnames. + ;; Two lists, strings, bit arrays, or pathnames are EQUAL if they have EQUAL + ;; elements. + (true-or-false? ____ (equal 'a 'a)) + (true-or-false? ____ (equal 3 3)) + (true-or-false? ____ (equal 3 3.0)) + (true-or-false? ____ (equal '(1 2) '(1 2))) + (true-or-false? ____ (equal '(:a . :b) '(:a . :b))) + (true-or-false? ____ (equal '(:a . :b) '(:a . :doesnt-match))) + (true-or-false? ____ (equal #\S #\S)) + (true-or-false? ____ (equal "Foo" "Foo")) + (true-or-false? ____ (equal #*01010101 #*01010101)) + (true-or-false? ____ (equal "Foo" (copy-seq "Foo"))) + (true-or-false? ____ (equal "FOO" "Foo")) + (true-or-false? ____ (equal #p"foo/bar/baz" #p"foo/bar/baz"))) -(define-test test-numeric-equal - "(= x y) is only for numerics - and can take multiple arguments - if x or y is not numeric there will be a compiler error." - (true-or-false? ___ (= 99.0 99 99.000)) - (true-or-false? ___ (= 0 1 -1)) - (true-or-false? ___ (= (/ 2 3) (/ 6 9) (/ 86 129)))) +(defstruct thing slot-1 slot-2) -; EQ, EQL, EQUAL, and EQUALP are general equality predicates. -; Additionally, Lisp also provides the type-specific predicates. -; For example, STRING= and STRING-EQUAL are predicates for strings. -(define-test test-string-equal - "string-equal is just like string= except that differences in case are ignored." - (true-or-false? ___ (string= "Foo" "Foo")) - (true-or-false? ___ (string= "Foo" "FOO")) - (true-or-false? ___ (string= "together" "frog" :start1 1 :end1 3 :start2 2)) - (true-or-false? ___ (string-equal "Foo" "FOO")) - (true-or-false? ___ (string-equal "together" "FROG" :start1 1 :end1 3 :start2 2))) +(define-test equalp + ;; EQUALP works like EQUAL, except it works differently for characters, + ;; numbers, arrays, structures, and hash tables. + ;; Two characters are EQUALP if they represent the same character, ignoring + ;; the differences in character case. + ;; Two numbers are EQUALP if they represent the same number, even if they are + ;; of different types. + ;; Two arrays are EQUALP if they have the same dimensions and their characters + ;; are pairwise EQUALP. + ;; Two structures are EQUALP if they are of the same class and their slots are + ;; pairwise EQUALP. + ;; We will contemplate hash tables in the HASH-TABLES lesson. + (true-or-false? ____ (equalp 'a 'a)) + (true-or-false? ____ (equalp 3 3)) + (true-or-false? ____ (equalp 3 3.0)) + (true-or-false? ____ (equalp '(1 2) '(1 2))) + (true-or-false? ____ (equalp '(:a . :b) '(:a . :b))) + (true-or-false? ____ (equalp '(:a . :b) '(:a . :doesnt-match))) + (true-or-false? ____ (equalp #\S #\S)) + (true-or-false? ____ (equalp "Foo" "Foo")) + (true-or-false? ____ (equalp "Foo" (copy-seq "Foo"))) + (true-or-false? ____ (equalp "FOO" "Foo")) + (true-or-false? ____ (equalp (make-array '(4 2) :initial-element 0) + (make-array '(4 2) :initial-element 0))) + (true-or-false? ____ (equalp (make-thing :slot-1 42 :slot-2 :forty-two) + (make-thing :slot-1 42 :slot-2 :forty-two)))) + +;;; In additional to the generic equality predicates, Lisp also provides +;;; type-specific predicates for numbers, strings, and characters. + +(define-test = + ;; The function = behaves just like EQUALP on numbers. + ;; #C(... ...) is syntax sugar for creating a complex number. + (true-or-false? ____ (= 99.0 99 99.000 #C(99 0) #C(99.0 0.0))) + (true-or-false? ____ (= 0 1 -1)) + (true-or-false? ____ (= (/ 2 3) (/ 6 9) (/ 86 129)))) + +(define-test string= + ;; The function STRING= behaves just like EQUAL on strings. + ;; The function STRING-EQUAL behaves just like EQUALP on strings. + (true-or-false? ____ (string= "Foo" "Foo")) + (true-or-false? ____ (string= "Foo" "FOO")) + (true-or-false? ____ (string-equal "Foo" "FOO")) + ;; These functions accept additional keyword arguments that allow one to + ;; only compare parts of the strings. + (true-or-false? ____ (string= "together" "frog" :start1 1 :end1 3 + :start2 2)) + (true-or-false? ____ (string-equal "together" "FROG" :start1 1 :end1 3 + :start2 2))) + +(define-test char= + ;; The function CHAR= behaves just like EQL on characters. + ;; The function CHAR-EQUAL behaves just like EQUALP on characters. + (true-or-false? ____ (char= #\A (char "ABCDEF" 0))) + (true-or-false? ____ (char= #\A #\a)) + (true-or-false? ____ (char-equal #\A (char "ABCDEF" 0))) + (true-or-false? ____ (char-equal #\A #\a))) diff --git a/koans/hash-tables.lisp b/koans/hash-tables.lisp index 17ed0b90..485d4092 100644 --- a/koans/hash-tables.lisp +++ b/koans/hash-tables.lisp @@ -1,128 +1,105 @@ -;; 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. - - -; based on python koans: about_dictionaries.py - - -(define-test test-create-hash-table - "make hash table with make-hash-table" - (let ((my-hash-table)) - (setf my-hash-table (make-hash-table)) - (true-or-false? ___ (typep my-hash-table 'hash-table)) - (true-or-false? ___ (hash-table-p my-hash-table)) - (true-or-false? ___ (hash-table-p (make-array '(3 3 3)))) - (assert-equal ___ (hash-table-count my-hash-table)))) - - -(define-test test-hash-table-access - "gethash is for accessing hash tables" - (let ((table-of-cube-roots (make-hash-table))) - - "assign the key-value pair 1->'uno'" - (setf (gethash 1 table-of-cube-roots) "uno") - (assert-equal "uno" (gethash 1 table-of-cube-roots)) - (assert-equal 1 (hash-table-count table-of-cube-roots)) - - (setf (gethash 8 table-of-cube-roots) 2) - (setf (gethash -3 table-of-cube-roots) -27) - (assert-equal ___ (gethash -3 table-of-cube-roots)) - (assert-equal ___ (hash-table-count table-of-cube-roots)) - - "accessing unset keys returns nil" - (assert-equal ___ (gethash 125 table-of-cube-roots)))) - - -(define-test test-hash-key-equality - "hash tables need to know how to tell if two keys are equivalent. - The programmer must be careful to know which equality predicate is right." - (let ((hash-table-eq nil) - (hash-table-equal nil) - (hash-table-default nil)) - - "define three hash tables, with different equality tests" - (setf hash-table-eq (make-hash-table :test #'eq)) - (setf hash-table-equal (make-hash-table :test #'equal)) - (setf hash-table-default (make-hash-table)) - - "add the same string twice, to each" - (setf (gethash "one" hash-table-eq) "uno") - (setf (gethash "one" hash-table-eq) "uno") - - (setf (gethash "one" hash-table-equal) "uno") - (setf (gethash "one" hash-table-equal) "uno") - - (setf (gethash "one" hash-table-default) "uno") - (setf (gethash "one" hash-table-default) "uno") - - "count how many unique key-value pairs in each" - (assert-equal ___ (hash-table-count hash-table-eq)) - (assert-equal ___ (hash-table-count hash-table-equal)) - (assert-equal ___ (hash-table-count hash-table-default)))) - - -(define-test test-hash-table-equality - (let ((h1 (make-hash-table :test #'equal)) - (h2 (make-hash-table :test #'equal))) - (setf (gethash "one" h1) "yat") - (setf (gethash "one" h2) "yat") - (setf (gethash "two" h1) "yi") - (setf (gethash "two" h2) "yi") - (true-or-false? ___ (eq h1 h2)) - (true-or-false? ___ (equal h1 h2)) - (true-or-false? ___ (equalp h1 h2)))) - - -(define-test test-changing-hash-tables - (let ((babel-fish (make-hash-table :test #'equal)) - (expected (make-hash-table :test #'equal))) - (setf (gethash "one" babel-fish) "uno") - (setf (gethash "two" babel-fish) "dos") - (setf (gethash "one" expected) "eins") - (setf (gethash "two" expected) "zwei") - - (setf (gethash "one" babel-fish) "eins") - (setf (gethash "two" babel-fish) ____) - - (assert-true (equalp babel-fish expected)))) - - -(define-test test-hash-key-membership - "hash tables use multiple value return to tell you if the key exists" - (let ((prev-pres (make-hash-table :test #'equal)) - (value-and-exists nil)) - (setf (gethash "Obama" prev-pres) "Bush") - (setf (gethash "Lincoln" prev-pres) "Buchanan") - (setf (gethash "Washington" prev-pres) nil) - - (setf value-and-exists (multiple-value-list (gethash "Obama" prev-pres))) - (assert-equal value-and-exists '("Bush" t)) - (setf value-and-exists (multiple-value-list (gethash "Lincoln" prev-pres))) - (assert-equal value-and-exists ____) - (setf value-and-exists (multiple-value-list (gethash "Washington" prev-pres))) - (assert-equal value-and-exists ____) - (setf value-and-exists (multiple-value-list (gethash "Franklin" prev-pres))) - (assert-equal value-and-exists ____))) - +;;; 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. + +;;; A hash table data structure is sometimes known as a dictionary. + +(define-test make-hash-table + (let ((my-hash-table (make-hash-table))) + (true-or-false? ____ (typep my-hash-table 'hash-table)) + (true-or-false? ____ (hash-table-p my-hash-table)) + (true-or-false? ____ (hash-table-p (make-array '(3 3 3)))) + ;; The function HASH-TABLE-COUNT returns the number of entries currently + ;; contained in a hash table. + (assert-equal ____ (hash-table-count my-hash-table)))) + +(define-test gethash + ;; The function GETHASH can be used to access hash table values. + (let ((cube-roots (make-hash-table))) + ;; We add the key-value pair 1 - "uno" to the hash table. + (setf (gethash 1 cube-roots) "uno") + (assert-equal ____ (gethash 1 cube-roots)) + (assert-equal ____ (hash-table-count cube-roots)) + (setf (gethash 8 cube-roots) 2) + (setf (gethash -3 cube-roots) -27) + (assert-equal ____ (gethash -3 cube-roots)) + (assert-equal ____ (hash-table-count cube-roots)) + ;; GETHASH returns a secondary value that is true if the key was found in + ;; the hash-table and false otherwise. + (multiple-value-bind (value foundp) (gethash 8 cube-roots) + (assert-equal ____ value) + (assert-equal ____ foundp)) + (multiple-value-bind (value foundp) (gethash 125 cube-roots) + (assert-equal ____ value) + (assert-equal ____ foundp)))) + +(define-test hash-table-test + ;; A hash table can be constructed with different test predicates. + ;; The programmer may choose between EQ, EQL, EQUAL, and EQUALP to get the + ;; best performance and expected results from the hash table. + ;; The default test predicate is EQL. + (let ((eq-table (make-hash-table :test #'eq)) + (eql-table (make-hash-table)) + (equal-table (make-hash-table :test #'equal)) + (equalp-table (make-hash-table :test #'equalp))) + ;; We will define four variables whose values are strings. + (let ((string "one") + (same-string string) + (string-copy (copy-string string)) + (string-upcased "ONE"))) + ;; We will insert the value of each variable into each hash table. + (dolist (thing (list string same-string string-copy string-upcased)) + (dolist (hash-table (list eq-table eql-table equal-table equalp-table)) + (setf (gethash string hash-table) t))) + ;; How many entries does each hash table contain? + (assert-equal ____ (hash-table-count eq-table)) + (assert-equal ____ (hash-table-count eql-table)) + (assert-equal ____ (hash-table-count equal-table)) + (assert-equal ____ (hash-table-count equalp-table)))) + +(define-test hash-table-equality + ;; EQUALP considers two hash tables to be equal if they have the same test and + ;; if its key-value pairs are the same under that test. + (let ((hash-table-1 (make-hash-table :test #'equal)) + (hash-table-2 (make-hash-table :test #'equal))) + (setf (gethash "one" hash-table-1) "yat") + (setf (gethash "one" hash-table-2) "yat") + (setf (gethash "two" hash-table-1) "yi") + (setf (gethash "two" hash-table-2) "yi") + (true-or-false? ____ (eq hash-table-1 hash-table-2)) + (true-or-false? ____ (equal hash-table-1 hash-table-2)) + (true-or-false? ____ (equalp hash-table-1 hash-table-2)))) + +(define-test i-will-make-it-equalp + (let ((hash-table-1 (make-hash-table :test #'equal)) + (hash-table-2 (make-hash-table :test #'equal))) + (setf (gethash "one" hash-table-1) "uno" + (gethash "two" hash-table-1) "dos") + (setf (gethash "one" hash-table-2) "eins" + (gethash "two" hash-table-2) "zwei") + (assert-false (equalp hash-table-1 hash-table-2)) + ;; Change the first hash table to be EQUALP to the second one. + (setf (gethash ____ hash-table-1) ____ + (gethash ____ hash-table-1) ____) + (assert-true (equalp hash-table-1 hash-table-2)))) (define-test test-make-your-own-hash-table - "make a hash table that meets the following conditions" - (let ((colors (make-hash-table)) - values) - + ;; Make your own hash table that satisfies the test. + (let ((colors ____)) + ;; You will need to modify your hash table after you create it. + ____ (assert-equal (hash-table-count colors) 4) - (setf values (list (gethash "blue" colors) - (gethash "green" colors) - (gethash "red" colors))) - (assert-equal values '((0 0 1) (0 1 0) (1 0 0))))) + (let ((values (list (gethash "blue" colors) + (gethash "green" colors) + (gethash "red" colors)))) + (assert-equal values '((0 0 1) (0 1 0) (1 0 0)))))) diff --git a/koans/lists.lisp b/koans/lists.lisp index 5cdc4e69..bc1d8d96 100644 --- a/koans/lists.lisp +++ b/koans/lists.lisp @@ -64,30 +64,6 @@ (assert-equal ____ (cadr x)) (assert-equal ____ (cdaadr x)))) -(define-test cons-tructing-improper-lists - ;; A proper list is a list whose final CDR ends with NIL. - ;; An improper list either has a non-NIL value in its final CDR or does not - ;; have a final CDR due to a cycle in its structure. - (let (;; We can construct non-cyclic improper lists using LIST*... - (x (list* 1 2 3 4 5)) - ;; ...or pass them as literals via dot notation. - (y '(6 7 8 9 . 0))) - ;; The function LAST returns the last cons cell of a list. - (assert-equal ____ (last x)) - (assert-equal ____ (list y))) - ;; We can create a cyclic list by changing the last CDR of a list to refer to - ;; another cons cell - (let ((list (list 1 2 3 4 5)) - (cyclic-list (list 1 2 3 4 5))) - (setf (cdr (last cyclic-list)) cyclic-list) - ;; Function LIST-LENGTH returns NIL if a list is cyclic. - (assert-equal ____ (list-length list)) - (assert-equal ____ (list-length cyclic-list)) - ;; Many Lisp functions operate only on proper lists. - ;; The function NTH is not one of them; it can be used to retrieve elements - ;; of cyclic lists. - (assert-equal ____ (nth 101 cyclic-list)))) - (define-test push-pop ;; PUSH and POP are macros similar to SETF, as both of them operate on places. (let ((place '(10 20 30 40))) @@ -126,31 +102,45 @@ (define-test test-accessing-list-elements (let ((noms '("peanut" "butter" "and" "jelly"))) + ;; Common Lisp defines accessor functions for lists: FIRST, SECOND, ..., + ;; up to TENTH. (assert-equal "peanut" (first noms)) - (assert-equal ___ (second noms)) - (assert-equal ___ (fourth noms)) - "last returns a singleton list of the final element" - (assert-equal ___ (last noms)) - (assert-equal "butter" (nth 1 noms)) ; k 1 - (assert-equal ___ (nth 0 noms)) - (assert-equal ___ (nth 2 noms)) - "'elt' is similar to 'nth', with the arguments reversed" - (assert-equal ___ (elt noms 2)))) + (assert-equal ____ (second noms)) + (assert-equal ____ (fourth noms)) + ;; The function LAST returns the last cons cell of a list. + (assert-equal ____ (last noms)) + ;; The function NTH returns the n-th element of a list. + (assert-equal "butter" (nth 1 noms)) + (assert-equal ____ (nth 0 noms)) + (assert-equal ____ (nth 3 noms)))) +(define-test cons-tructing-improper-lists + ;; A proper list is a list whose final CDR ends with NIL. + ;; An improper list either has a non-NIL value in its final CDR or does not + ;; have a final CDR due to a cycle in its structure. + (let (;; We can construct non-cyclic improper lists using LIST*... + (x (list* 1 2 3 4 5)) + ;; ...or pass them as literals via dot notation. + (y '(6 7 8 9 . 0))) + (assert-equal ____ (last x)) + (assert-equal ____ (list y))) + ;; We can create a cyclic list by changing the last CDR of a list to refer to + ;; another cons cell + (let ((list (list 1 2 3 4 5)) + (cyclic-list (list 1 2 3 4 5))) + (setf (cdr (last cyclic-list)) cyclic-list) + ;; Function LIST-LENGTH returns NIL if a list is cyclic. + (assert-equal ____ (list-length list)) + (assert-equal ____ (list-length cyclic-list)) + ;; Many Lisp functions operate only on proper lists. + ;; The function NTH is not one of them; it can be used to retrieve elements + ;; of cyclic lists. + (assert-equal ____ (nth 101 cyclic-list)))) (define-test test-slicing-lists - (let ((noms '("peanut" "butter" "and" "jelly"))) - (assert-equal ___ (subseq noms 0 1)) - (assert-equal ___ (subseq noms 0 2)) - (assert-equal ___ (subseq noms 2 2)) - (assert-equal ___ (subseq noms 2)))) - - -(define-test test-list-breakdown - "car (aka. 'first') returns the first value in a list" - (assert-equal ___ (car '(1 2 3))) - (assert-equal ___ (car nil)) - "cdr (aka. 'rest') refers to the remainder of the list, - after the first element" - (assert-equal ___ (cdr '(1 2 3))) - (assert-equal ___ (cdr nil))) + ;; The function SUBSEQ returns a subsequence of a list. + (let ((noms (list "peanut" "butter" "and" "jelly"))) + (assert-equal ____ (subseq noms 0 1)) + (assert-equal ____ (subseq noms 0 2)) + (assert-equal ____ (subseq noms 2 2)) + (assert-equal ____ (subseq noms 2)))) diff --git a/koans/multiple-values.lisp b/koans/multiple-values.lisp index fafbfbff..b98014e9 100644 --- a/koans/multiple-values.lisp +++ b/koans/multiple-values.lisp @@ -1,48 +1,41 @@ -;; 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. +;;; 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. +;;; In Lisp, it is possible for a function to return more than one value. +;;; This is distinct from returning a list or structure of values. - -"In lisp, it is possible for a function to return more than one value. -This is distinct from returning a list or structure of values." - -(define-test test-floor-returns-multiple-values - (let ((x) - (y)) - (setf x (floor 1.5)) - (assert-equal x 1) - (setf x (multiple-value-list (floor 3/2))) - (assert-equal x '(1 1/2))) - (assert-equal (multiple-value-list (floor 99/4)) ____)) +(define-test multiple-values + (let ((x (floor 3/2)) + ;; The macro MULTIPLE-VALUE-LIST returns a list of all values returned + ;; by a Lisp form. + (y (multiple-value-list (floor 3/2)))) + (assert-equal x 1) + (assert-equal y '(1 1/2))) + (assert-equal ____ (multiple-value-list (floor 99/4)))) (defun next-fib (a b) + ;; The function VALUES allows returning multiple values. (values b (+ a b))) -(define-test test-multi-value-bind - (let ((x) - (y)) - (setf x (next-fib 2 3)) - (assert-equal x ___) - (setf x (multiple-value-list (next-fib 2 3))) - (assert-equal x ___) - "multiple-value-bind binds the variables in the first form - to the outputs of the second form. And then returns the output - of the third form using those bindings" - (setf y (multiple-value-bind (b c) (next-fib 3 5) (* b c))) - (assert-equal y ___) - "multiple-value-setq is like setf, but can set multiple variables" - (multiple-value-setq (x y) (values :v1 :v2)) - (assert-equal (list x y) '(:v1 :v2)) - (multiple-value-setq (x y) (next-fib 5 8)) - (assert-equal (list x y) ____))) +(define-test binding-and-setting-multiple-values + ;; The macro MULTIPLE-VALUE-BIND is like LET, except it binds the variables + ;; listed in its first argument to the values returned by the form in its + ;; second argument. + (multiple-value-bind (x y) (next-fib 3 5) + (let ((result (* x y))) + (assert-equal ____ result))) + ;; SETF can also set multiple values if a VALUES form is provided as a place. + (let (x y) + (setf (values x y) (next-fib 5 8)) + (assert-equal ____ (list x y)))) diff --git a/koans/vectors.lisp b/koans/vectors.lisp index 751116d2..70cb0b09 100644 --- a/koans/vectors.lisp +++ b/koans/vectors.lisp @@ -1,47 +1,50 @@ -;; 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. - -"vectors are just like rank 1 arrays" - -(define-test test-vector-types - " #(x y z) defines a vector literal containing x y z" - (true-or-false? ___ (typep #(1 11 111) 'vector)) - (assert-equal ___ (aref #(1 11 111) 1))) - - -(define-test test-length-works-on-vectors - (assert-equal (length #(1 2 3)) ___ )) - - -(define-test test-bit-vector - "#*0011 defines a bit vector literal with four elements, 0, 0, 1 and 1" - (assert-equal #*0011 (make-array '4 :element-type 'bit)) +;;; 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. + +;;; Vectors are one-dimensional arrays. This means that general array operations +;;; will work on vectors normally. However, Lisp also defines some functions for +;;; operating on sequences - which means, either vectors or lists. + +(define-test vector-basics + ;; #(...) is syntax sugar for defining literal vectors. + (let ((vector #(1 11 111))) + (true-or-false? ____ (typep vector 'vector)) + (assert-equal ____ (aref vector 1)))) + +(define-test length + ;; The function LENGTH works both for vectors and for lists. + (assert-equal ____ (length '(1 2 3))) + (assert-equal ____ (length #(1 2 3)))) + +(define-test bit-vector + ;; #*0011 defines a bit vector literal with four elements: 0, 0, 1 and 1. + (assert-equal #*0011 (make-array 4 :element-type 'bit :initial-contents ____)) (true-or-false? ____ (typep #*1001 'bit-vector)) (assert-equal ____ (aref #*1001 1))) +(define-test bitwise-operations + ;; Lisp defines a few bitwise operations that work on bit vectors. + (assert-equal ____ (bit-and #*1100 #*1010)) + (assert-equal ____ (bit-ior #*1100 #*1010)) + (assert-equal ____ (bit-xor #*1100 #*1010))) -(define-test test-some-bitwise-operations - (assert-equal ___ (bit-and #*1100 #*1010)) - (assert-equal ___ (bit-ior #*1100 #*1010)) - (assert-equal ___ (bit-xor #*1100 #*1010))) +(defun list-to-bit-vector (list) + ;; Implement a function that turns a list into a bit vector. + ____) - -(defun list-to-bit-vector (my-list) - nil) - -(define-test test-list-to-bit-vector - "you must complete list-to-bit-vector" +(define-test list-to-bit-vector + ;; You need to fill in the blank in LIST-TO-BIT-VECTOR. (assert-true (typep (list-to-bit-vector '(0 0 1 1 0)) 'bit-vector)) (assert-equal (aref (list-to-bit-vector '(0)) 0) 0) (assert-equal (aref (list-to-bit-vector '(0 1)) 1) 1)