learning koans
- refreshed understanding of lexical vs. dynamic binding https://gigamonkeys.com/book/variables.html - was taught CASE as simpler variant of COND
This commit is contained in:
parent
49c00c24ee
commit
fd03924c10
|
@ -28,38 +28,38 @@
|
|||
;;; Sometimes, you will be asked to provide values that are equal to something.
|
||||
|
||||
(define-test fill-in-the-blanks
|
||||
(assert-equal ____ 2)
|
||||
(assert-equal ____ 3.14)
|
||||
(assert-equal ____ "Hello World"))
|
||||
(assert-equal 2 2)
|
||||
(assert-equal 3.14 3.14)
|
||||
(assert-equal "Hello World" "Hello World"))
|
||||
|
||||
;;; Sometimes, you will be asked to say whether something is true or false,
|
||||
;;; In Common Lisp, the canonical values for truth and falsehood are T and NIL.
|
||||
|
||||
(define-test assert-true
|
||||
(assert-true ____))
|
||||
(assert-true t))
|
||||
|
||||
(define-test assert-false
|
||||
(assert-false ____))
|
||||
(assert-false nil))
|
||||
|
||||
;; could use C-x C-e (sly-eval-last-expression) to eval just (= 34 34) to check whether T or NIL returns
|
||||
(define-test true-or-false
|
||||
(true-or-false? ____ (= 34 34))
|
||||
(true-or-false? ____ (= 19 78)))
|
||||
(true-or-false? t (= 34 34))
|
||||
(true-or-false? nil (= 19 78)))
|
||||
|
||||
;;; Since T and NIL are symbols, you can type them in lowercase or uppercase;
|
||||
;;; by default, Common Lisp will automatically upcase them upon reading.
|
||||
|
||||
(define-test upcase-downcase
|
||||
;; Try inserting a lowercase t here.
|
||||
(assert-equal ____ T)
|
||||
(assert-equal t T)
|
||||
;; Try inserting an uppercase NIL here.
|
||||
(assert-equal ____ nil))
|
||||
(assert-equal NIL nil))
|
||||
|
||||
;;; Sometimes, you will be asked to provide a part of an expression that must be
|
||||
;;; either true or false.
|
||||
|
||||
(define-test a-true-assertion
|
||||
(assert-true (= ____ (+ 2 2))))
|
||||
(assert-true (= 4 (+ 2 2))))
|
||||
|
||||
(define-test a-false-assertion
|
||||
(assert-false (= ____ (+ 2 2))))
|
||||
|
||||
(assert-false (= 3 (+ 2 2))))
|
||||
|
|
|
@ -19,25 +19,25 @@
|
|||
(define-test list-or-atom
|
||||
;; The function LISTP will return true if the input is a list.
|
||||
;; The function ATOM will return true if the input is an atom.
|
||||
(true-or-false? ____ (listp '(1 2 3)))
|
||||
(true-or-false? ____ (atom '(1 2 3)))
|
||||
(true-or-false? ____ (listp '("heres" "some" "strings")))
|
||||
(true-or-false? ____ (atom '("heres" "some" "strings")))
|
||||
(true-or-false? ____ (listp "a string"))
|
||||
(true-or-false? ____ (atom "a string"))
|
||||
(true-or-false? ____ (listp 2))
|
||||
(true-or-false? ____ (atom 2))
|
||||
(true-or-false? ____ (listp '(("first" "list") ("second" "list"))))
|
||||
(true-or-false? ____ (atom '(("first" "list") ("second" "list")))))
|
||||
(true-or-false? t (listp '(1 2 3)))
|
||||
(true-or-false? nil (atom '(1 2 3)))
|
||||
(true-or-false? t (listp '("heres" "some" "strings")))
|
||||
(true-or-false? nil (atom '("heres" "some" "strings")))
|
||||
(true-or-false? nil (listp "a string"))
|
||||
(true-or-false? t (atom "a string"))
|
||||
(true-or-false? nil (listp 2))
|
||||
(true-or-false? t (atom 2))
|
||||
(true-or-false? t (listp '(("first" "list") ("second" "list"))))
|
||||
(true-or-false? nil (atom '(("first" "list") ("second" "list")))))
|
||||
|
||||
(define-test the-duality-of-nil
|
||||
;; The empty list, NIL, is unique in that it is both a list and an atom.
|
||||
(true-or-false? ____ (listp nil))
|
||||
(true-or-false? ____ (atom nil)))
|
||||
(true-or-false? t (listp nil))
|
||||
(true-or-false? t (atom nil)))
|
||||
|
||||
(define-test keywords
|
||||
;; Symbols like :HELLO or :LIKE-THIS are keywords. They are treated
|
||||
;; differently in Lisp: they are constants that always evaluate to themselves.
|
||||
(true-or-false? ____ (equal :this-is-a-keyword :this-is-a-keyword))
|
||||
(true-or-false? ____ (equal :this-is-a-keyword ':this-is-a-keyword))
|
||||
(true-or-false? ____ (equal :this-is-a-keyword :this-is-also-a-keyword)))
|
||||
(true-or-false? t (equal :this-is-a-keyword :this-is-a-keyword))
|
||||
(true-or-false? t (equal :this-is-a-keyword ':this-is-a-keyword))
|
||||
(true-or-false? nil (equal :this-is-a-keyword :this-is-also-a-keyword)))
|
||||
|
|
|
@ -22,43 +22,49 @@
|
|||
(c (copy-seq "I am Tom.")))
|
||||
;; A place may be a variable.
|
||||
(setf a 1000)
|
||||
(assert-equal ____ a)
|
||||
(assert-equal 1000 a)
|
||||
;; A place may be a part of some list.
|
||||
(setf (first b) 10)
|
||||
(assert-equal ____ b)
|
||||
(assert-equal '(10 20 30 40 50) b)
|
||||
;; A place may be a character in a string.
|
||||
;; The #\x syntax denotes a single character, 'x'.
|
||||
(setf (char c 5) #\B
|
||||
(char c 7) #\b)
|
||||
(assert-equal ____ c)
|
||||
(assert-equal "I am Bob." c)
|
||||
;; There are other kinds of places that we will explore in the future.
|
||||
))
|
||||
|
||||
;;; looks like COND is much stronger
|
||||
;; while CASE only tests with some kind of equasion?
|
||||
;; with destructuringom as well?
|
||||
;; http://www.lispworks.com/documentation/HyperSpec/Body/m_case_.htm
|
||||
;; nope, not desctructuring, but can have check on belonging to a set
|
||||
;; http://www.lispworks.com/documentation/HyperSpec/Body/m_cond.htm
|
||||
(define-test case
|
||||
;; CASE is a simple pattern-matching macro, not unlike C's "switch".
|
||||
;; It compares an input against a set of values and evaluates the code for
|
||||
;; the branch where a match is found.
|
||||
(let* ((a 4)
|
||||
(b (case a
|
||||
(3 :three)
|
||||
(4 :four)
|
||||
(5 :five))))
|
||||
(assert-equal ____ b))
|
||||
;; CASE is a simple pattern-matching macro, not unlike C's "switch".
|
||||
;; It compares an input against a set of values and evaluates the code for
|
||||
;; the branch where a match is found.
|
||||
(let* ((a 4)
|
||||
(b (case a ; and the book have tought COND
|
||||
(3 :three)
|
||||
(4 :four)
|
||||
(5 :five))))
|
||||
(assert-equal :four b))
|
||||
;; CASE can accept a group of keys.
|
||||
(let* ((c 4)
|
||||
(d (case c
|
||||
((0 2 4 6 8) :even-digit)
|
||||
((1 3 5 7 9) :odd-digit))))
|
||||
(assert-equal ____ d)))
|
||||
(assert-equal :even-digit d)))
|
||||
|
||||
(defun match-special-cases (thing)
|
||||
;; T or OTHERWISE passed as the key matches any value.
|
||||
;; NIL passed as the key matches no values.
|
||||
;; These symbols need to passed in parentheses.
|
||||
(case thing
|
||||
(____ :found-a-t)
|
||||
(____ :found-a-nil)
|
||||
(____ :something-else)))
|
||||
((t) :found-a-t)
|
||||
((nil) :found-a-nil)
|
||||
(otherwise :something-else)))
|
||||
|
||||
(define-test special-cases-of-case
|
||||
;; You need to fill in the blanks in MATCH-SPECIAL-CASES.
|
||||
|
@ -71,9 +77,9 @@
|
|||
(flet ((cartoon-dads (input)
|
||||
(case input
|
||||
;; Fill in the blanks with proper cases.
|
||||
____
|
||||
____
|
||||
____
|
||||
((:bart :lisa) :homer)
|
||||
(:stewie :peter)
|
||||
(:stan :randy)
|
||||
(:this-one-doesnt-happen :fancy-cat)
|
||||
(t :unknown))))
|
||||
(assert-equal (cartoon-dads :bart) :homer)
|
||||
|
@ -91,14 +97,14 @@
|
|||
(string-copy (copy-seq string)))
|
||||
;; The above means that two distinct strings will not be the same under EQL,
|
||||
;; even if they have the same contents.
|
||||
(true-or-false? ____ (eql string string-copy))
|
||||
(true-or-false? ____ (equal string string-copy))
|
||||
(true-or-false? nil (eql string string-copy))
|
||||
(true-or-false? t (equal string string-copy))
|
||||
;; The above also means that CASE might give surprising results when used on
|
||||
;; strings.
|
||||
(let ((match (case string
|
||||
("A string" :matched)
|
||||
(t :not-matched))))
|
||||
(assert-equal ____ match))
|
||||
(assert-equal :not-matched match))
|
||||
;; We will explore this topic further in the EQUALITY-DISTINCTIONS lesson.
|
||||
))
|
||||
|
||||
|
@ -109,4 +115,4 @@
|
|||
(result (cond ((> number 0) :positive)
|
||||
((< number 0) :negative)
|
||||
(t :zero))))
|
||||
(assert-equal ____ result)))
|
||||
(assert-equal :positive result)))
|
||||
|
|
|
@ -19,30 +19,30 @@
|
|||
|
||||
(define-test function-names
|
||||
;; In these examples, +, -, *, and / are function names.
|
||||
(assert-equal ____ (+ 2 3))
|
||||
(assert-equal ____ (- 1 3))
|
||||
(assert-equal ____ (* 7 4))
|
||||
(assert-equal ____ (/ 100 4)))
|
||||
(assert-equal 5 (+ 2 3))
|
||||
(assert-equal -2 (- 1 3))
|
||||
(assert-equal 28 (* 7 4))
|
||||
(assert-equal 25 (/ 100 4)))
|
||||
|
||||
(define-test numberp
|
||||
;; NUMBERP is a predicate which returns true if its argument is a number.
|
||||
(assert-equal ____ (numberp 5))
|
||||
(assert-equal ____ (numberp 2.0))
|
||||
(assert-equal ____ (numberp "five")))
|
||||
(assert-equal t (numberp 5))
|
||||
(assert-equal t (numberp 2.0))
|
||||
(assert-equal nil (numberp "five")))
|
||||
|
||||
(define-test evaluation-order
|
||||
;; Arguments to a function are evaluated before the function is called.
|
||||
(assert-equal ____ (* (+ 1 2) (- 13 10))))
|
||||
(assert-equal 9 (* (+ 1 2) (- 13 10))))
|
||||
|
||||
(define-test basic-comparisons
|
||||
;; The below functions are boolean functions (predicates) that operate on
|
||||
;; numbers.
|
||||
(assert-equal ____ (> 25 4))
|
||||
(assert-equal ____ (< 8 2))
|
||||
(assert-equal ____ (= 3 3))
|
||||
(assert-equal ____ (<= 6 (/ 12 2)))
|
||||
(assert-equal ____ (>= 20 (+ 1 2 3 4 5)))
|
||||
(assert-equal ____ (/= 15 (+ 4 10))))
|
||||
(assert-equal t (> 25 4))
|
||||
(assert-equal nil (< 8 2))
|
||||
(assert-equal t (= 3 3))
|
||||
(assert-equal t (<= 6 (/ 12 2)))
|
||||
(assert-equal t (>= 20 (+ 1 2 3 4 5)))
|
||||
(assert-equal t (/= 15 (+ 4 10))))
|
||||
|
||||
(define-test quote
|
||||
;; Preceding a list with a quote (') will tell Lisp not to evaluate a list.
|
||||
|
@ -50,17 +50,17 @@
|
|||
;; the literal list.
|
||||
;; Evaluating the form (+ 1 2) returns the number 3, but evaluating the form
|
||||
;; '(+ 1 2) returns the list (+ 1 2).
|
||||
(assert-equal ____ (+ 1 2))
|
||||
(assert-equal ____ '(+ 1 2))
|
||||
(assert-equal ____ (list '+ 1 2))
|
||||
(assert-equal 3 (+ 1 2))
|
||||
(assert-equal '(+ 1 2) '(+ 1 2))
|
||||
(assert-equal '(+ 1 2) (list '+ 1 2))
|
||||
;; The 'X syntax is syntactic sugar for (QUOTE X).
|
||||
(true-or-false? ____ (equal '(/ 4 0) (quote (/ 4 0)))))
|
||||
(true-or-false? t (equal '(/ 4 0) (quote (/ 4 0)))))
|
||||
|
||||
(define-test listp
|
||||
;; LISTP is a predicate which returns true if the argument is a list.
|
||||
(assert-equal ____ (listp '(1 2 3)))
|
||||
(assert-equal ____ (listp 100))
|
||||
(assert-equal ____ (listp "Hello world"))
|
||||
(assert-equal ____ (listp nil))
|
||||
(assert-equal ____ (listp (+ 1 2)))
|
||||
(assert-equal ____ (listp '(+ 1 2))))
|
||||
(assert-equal t (listp '(1 2 3)))
|
||||
(assert-equal nil (listp 100))
|
||||
(assert-equal nil (listp "Hello world"))
|
||||
(assert-equal t (listp nil))
|
||||
(assert-equal nil (listp (+ 1 2)))
|
||||
(assert-equal t (listp '(+ 1 2))))
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
;; created: a symbol that names a variable becomes bound to a value.
|
||||
(let ((x 10)
|
||||
(y 20))
|
||||
(assert-equal ____ (+ x y))
|
||||
(assert-equal 30 (+ x y))
|
||||
;; It is possible to shadow previously visible bindings.
|
||||
(let ((y 30))
|
||||
(assert-equal ____ (+ x y)))
|
||||
(assert-equal ____ (+ x y)))
|
||||
(assert-equal 40 (+ x y)))
|
||||
(assert-equal 30 (+ x y)))
|
||||
;; Variables bound by LET have a default value of NIL.
|
||||
(let (x)
|
||||
(assert-equal ____ x)))
|
||||
(assert-equal nil x)))
|
||||
|
||||
(define-test let-versus-let*
|
||||
;; LET* is similar to LET, except the bindings are established sequentially,
|
||||
|
@ -33,30 +33,30 @@
|
|||
(y 20))
|
||||
(let ((x (+ y 100))
|
||||
(y (+ x 100)))
|
||||
(assert-equal ____ x)
|
||||
(assert-equal ____ y))
|
||||
(assert-equal 120 x)
|
||||
(assert-equal 110 y))
|
||||
(let* ((x (+ y 100))
|
||||
(y (+ x 100)))
|
||||
;; Which X is used to compute the value of Y?
|
||||
(assert-equal ____ x)
|
||||
(assert-equal ____ y))))
|
||||
(assert-equal 120 x)
|
||||
(assert-equal 220 y))))
|
||||
|
||||
(define-test let-it-be-equal
|
||||
;; Fill in the LET and LET* to get the tests to pass.
|
||||
(let ((a 1)
|
||||
(b :two)
|
||||
(c "Three"))
|
||||
(let ((____ ____)
|
||||
(____ ____)
|
||||
(____ ____))
|
||||
(let ((a 100)
|
||||
(b (* 200 a))
|
||||
(c "Jellyfish"))
|
||||
(assert-equal a 100)
|
||||
(assert-equal b 200)
|
||||
(assert-equal c "Jellyfish"))
|
||||
(let* ((____ ____)
|
||||
(____ ____)
|
||||
(let* ((a 121)
|
||||
(b (+ a 79))
|
||||
;; In this third binding, you are allowed to use the variables bound
|
||||
;; by the previous two LET* bindings.
|
||||
(____ ____))
|
||||
(c (+ a (/ b a))))
|
||||
(assert-equal a 121)
|
||||
(assert-equal b 200)
|
||||
(assert-equal c (+ a (/ b a))))))
|
||||
|
|
|
@ -14,39 +14,39 @@
|
|||
|
||||
(define-test t-and-nil-are-opposites
|
||||
;; NOT is a function which returns the boolean opposite of its argument.
|
||||
(true-or-false? ____ (not nil))
|
||||
(true-or-false? ____ (not t)))
|
||||
(true-or-false? t (not nil))
|
||||
(true-or-false? nil (not t)))
|
||||
|
||||
(define-test nil-and-empty-list-are-the-same-thing
|
||||
;; In Common Lisp, NIL is also the empty list.
|
||||
(true-or-false? ____ '())
|
||||
(true-or-false? ____ (not '())))
|
||||
(true-or-false? NIL '())
|
||||
(true-or-false? t (not '())))
|
||||
|
||||
(define-test in-lisp-many-things-are-true
|
||||
;; In Common Lisp, the canonical values for truth is T.
|
||||
;; However, everything that is non-NIL is true, too.
|
||||
(true-or-false? ____ 5)
|
||||
(true-or-false? ____ (not 5))
|
||||
(true-or-false? ____ "a string")
|
||||
(true-or-false? t 5)
|
||||
(true-or-false? nil (not 5))
|
||||
(true-or-false? t "a string")
|
||||
;; Even an empty string...
|
||||
(true-or-false? ____ "")
|
||||
(true-or-false? t "")
|
||||
;; ...or a list containing a NIL...
|
||||
(true-or-false? ____ (list nil))
|
||||
(true-or-false? t (list nil))
|
||||
;; ...or an array with no elements...
|
||||
(true-or-false? ____ (make-array 0))
|
||||
(true-or-false? t (make-array 0))
|
||||
;; ...or the number zero.
|
||||
(true-or-false? ____ 0))
|
||||
(true-or-false? t 0))
|
||||
|
||||
(define-test and
|
||||
;; The logical operator AND can take multiple arguments.
|
||||
(true-or-false? ____ (and t t t t t))
|
||||
(true-or-false? ____ (and t t nil t t))
|
||||
(true-or-false? t (and t t t t t))
|
||||
(true-or-false? nil (and t t nil t t))
|
||||
;; If all values passed to AND are true, it returns the last value.
|
||||
(assert-equal ____ (and t t t t t 5)))
|
||||
(assert-equal 5 (and t t t t t 5)))
|
||||
|
||||
(define-test or
|
||||
;; The logical operator OR can also take multiple arguments.
|
||||
(true-or-false? ____ (or nil nil nil t nil))
|
||||
(true-or-false? t (or nil nil nil t nil))
|
||||
;; OR returns the first non-NIL value it encounters, or NIL if there are none.
|
||||
(assert-equal ____ (or nil nil nil))
|
||||
(assert-equal ____ (or 1 2 3 4 5)))
|
||||
(assert-equal nil (or nil nil nil))
|
||||
(assert-equal 1 (or 1 2 3 4 5)))
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
;;; limitations under the License.
|
||||
|
||||
(define-test shadowing
|
||||
(assert-equal ____ (let ((z 4)) (list z (let ((z 2)) z)))))
|
||||
(assert-equal '(4 2) (let ((z 4)) (list z (let ((z 2)) z)))))
|
||||
|
||||
(defun block-1 ()
|
||||
(block here
|
||||
|
@ -28,19 +28,19 @@
|
|||
(return-from outer 'valve)))
|
||||
|
||||
(define-test block-return-from
|
||||
(assert-equal ____ (block-1))
|
||||
(assert-equal ____ (block-2)))
|
||||
(assert-equal 4 (block-1))
|
||||
(assert-equal 'space (block-2)))
|
||||
|
||||
;;; See http://www.gigamonkeys.com/book/variables.html
|
||||
|
||||
(define-test lexical-variables-can-be-enclosed
|
||||
(assert-equal ____ (let ((f (let ((x 10))
|
||||
(assert-equal 10 (let ((f (let ((x 10))
|
||||
(lambda () x))))
|
||||
(let ((x 20))
|
||||
(funcall f)))))
|
||||
|
||||
(define-test dynamic-variables-are-affected-by-execution-path
|
||||
(assert-equal ____ (let ((f (let ((x 10))
|
||||
(assert-equal 20 (let ((f (let ((x 10))
|
||||
(declare (special x))
|
||||
(lambda () x))))
|
||||
(let ((x 20))
|
||||
|
|
Loading…
Reference in New Issue