Skip to content

Commit

Permalink
More betterified koans
Browse files Browse the repository at this point in the history
  • Loading branch information
phoe committed May 6, 2020
1 parent bffb7bd commit 8ad95e7
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 379 deletions.
51 changes: 26 additions & 25 deletions koans/arrays.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand All @@ -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))))
27 changes: 13 additions & 14 deletions koans/basic-macros.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
201 changes: 115 additions & 86 deletions koans/equality-distinctions.lisp
Original file line number Diff line number Diff line change
@@ -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)))
Loading

0 comments on commit 8ad95e7

Please sign in to comment.