koans, stuff
dice - more practice with signal and clog backquote - first practice with @,a splicing macros - some news of common errors: - capturing outer symbols, so caller expects them to be used, but invisible internal values take their place - evaluating "pass by name" forms too many times - evaluating them in surprising order
This commit is contained in:
parent
cdeeb2fead
commit
063c5c52d1
|
@ -19,23 +19,26 @@
|
|||
(let ((x '(123))
|
||||
(z '(7 8 9)))
|
||||
;; ' quotes an expression normally.
|
||||
(assert-equal ____ '(x 45 6 z))
|
||||
(assert-equal (list '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 +46,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 +56,15 @@
|
|||
(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))))
|
||||
|
|
|
@ -18,16 +18,25 @@
|
|||
|
||||
(defclass dice-set ()
|
||||
;; Fill in the blank with a proper slot definition.
|
||||
(____))
|
||||
((dice-values :initarg :dice-values)))
|
||||
|
||||
(setq *my-dice* (make-instance 'dice-set :dice-values '(1 2 3 5)))
|
||||
(slot-value *my-dice* 'dice-values)
|
||||
|
||||
;;; This method might be unnecessary, depending on how you define the slots of
|
||||
;;; DICE-SET.
|
||||
|
||||
(defmethod dice-values ((object dice-set))
|
||||
____)
|
||||
(slot-value object 'dice-values))
|
||||
|
||||
(defmethod roll (count (object dice-set))
|
||||
____)
|
||||
(unless (and (integerp count) (< 0 count)) (signal (make-condition 'type-error
|
||||
:datum count
|
||||
:expected-type 'integer)))
|
||||
(let ((rolls (mapcar (lambda (x) (declare (ignore x)) (+ 1 (random 6))) (make-list count))))
|
||||
(setf (slot-value object 'dice-values) rolls)))
|
||||
|
||||
(roll 5 *my-dice*)
|
||||
|
||||
(define-test make-dice-set
|
||||
(let ((dice (make-instance 'dice-set)))
|
||||
|
@ -73,6 +82,12 @@
|
|||
(assert-equal 100 (length (roll 100 dice)))
|
||||
(assert-equal 1 (length (roll 1 dice)))))
|
||||
|
||||
;; this is about signaling error, rhg
|
||||
;; but wtf about expected-type being subtype of '(integer 1 6) ???
|
||||
;; shouldn't it be any integer?
|
||||
|
||||
|
||||
|
||||
(define-test junk-as-dice-count
|
||||
(let ((dice (make-instance 'dice-set)))
|
||||
(labels ((dice-failure (count)
|
||||
|
@ -84,10 +99,17 @@
|
|||
(expected-type (type-error-expected-type condition)))
|
||||
(assert-true (typep condition 'type-error))
|
||||
(assert-equal value (type-error-datum condition))
|
||||
(assert-true (subtypep '(integer 1 6) expected-type)))))
|
||||
(assert-true (subtypep '(integer 1 6) expected-type)) ; wtf is this?
|
||||
; surely it's got to be just integer?
|
||||
)))
|
||||
(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)))))
|
||||
|
||||
;; (setq dice *my-dice*)
|
||||
;; (dice-failure "0")
|
||||
|
||||
;;; welp. signaling errors is the most unfamiliar thing for me
|
||||
|
|
|
@ -23,4 +23,4 @@
|
|||
;;; This is a free form assignment, so approach it however you desire.
|
||||
|
||||
(define-test play-greed
|
||||
(assert-true ____))
|
||||
(assert-true t))
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
(cond ((null forms) 'nil)
|
||||
((null (rest forms)) (first forms))
|
||||
(t `(when ,(first forms)
|
||||
,(generate (rest forms)))))))
|
||||
,(generate (rest forms))))))) ; wowy
|
||||
(generate forms)))
|
||||
|
||||
(when (= 2 3) "hello")
|
||||
|
||||
(define-test my-and
|
||||
;; ASSERT-EXPANDS macroexpands the first form once and checks if it is equal
|
||||
;; to the second form.
|
||||
|
@ -35,7 +37,8 @@
|
|||
(= 0 (random 6))
|
||||
(= 0 (random 6))
|
||||
(error "Bang!"))
|
||||
____))
|
||||
'(when (= 0 (random 6))
|
||||
(when (= 0 (random 6)) (when (= 0 (random 6)) (error "Bang!"))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
@ -51,8 +54,11 @@
|
|||
(result '()))
|
||||
(for (i 0 3)
|
||||
(push i result)
|
||||
(assert-equal ____ limit))
|
||||
(assert-equal ____ (nreverse result)))))
|
||||
(assert-equal 3 limit))
|
||||
(assert-equal '(0 1 2 3) (nreverse result))))) ; didn't get it on first tries, ugh
|
||||
;; oh, ok - then try to use names that wouldn't happen in outside condext
|
||||
;; so that explicitly defined things in outside context get overshadowed
|
||||
;; ok
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
@ -72,8 +78,11 @@
|
|||
(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)))))
|
||||
(assert-equal '(0 1 2 3) (nreverse result))
|
||||
(assert-equal '(0 3 3 3 3 3) (nreverse side-effects)))))
|
||||
; omg, fuck this guessing
|
||||
; ok, the ,stop was evaluated on each iteraction
|
||||
; to check "whether to stop"
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
@ -96,8 +105,10 @@
|
|||
(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)))))
|
||||
(assert-equal '(0 1 2 3) (nreverse result))
|
||||
(assert-equal '(3 0) (nreverse side-effects)))))
|
||||
;; didn't got on first try,
|
||||
;; but yes, for gensym limit ,stop is evaluated first
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
@ -105,7 +116,13 @@
|
|||
(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 ((initial (gensym "INITIAL"))
|
||||
(limit (gensym "LIMIT")))
|
||||
`(do* ((,initial ,start)
|
||||
(,limit ,stop)
|
||||
(,var ,initial (1+ ,var)))
|
||||
((> ,var ,limit))
|
||||
,@body))))
|
||||
(let ((side-effects '())
|
||||
(result '()))
|
||||
(flet ((return-0 () (push 0 side-effects) 0)
|
||||
|
@ -114,3 +131,12 @@
|
|||
(push i result)))
|
||||
(assert-equal '(0 1 2 3) (nreverse result))
|
||||
(assert-equal '(0 3) (nreverse side-effects)))))
|
||||
|
||||
;; (do* ((a (return-0))
|
||||
;; (b (return-3))
|
||||
;; (i a (1+ i)))
|
||||
;; ((> i b))
|
||||
;; (push i result))
|
||||
;;
|
||||
;; so, my mistake was: using DO and trying to cross reference temp vars
|
||||
;; and mistyping 1+ as 1_
|
||||
|
|
Loading…
Reference in New Issue