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:
efim 2022-07-24 13:18:22 +00:00
parent 49c00c24ee
commit fd03924c10
7 changed files with 116 additions and 110 deletions

View File

@ -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))))

View File

@ -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)))

View File

@ -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
(b (case a ; and the book have tought COND
(3 :three)
(4 :four)
(5 :five))))
(assert-equal ____ b))
(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)))

View File

@ -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))))

View File

@ -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))))))

View File

@ -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)))

View File

@ -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))