From 9c64cf128f6dffa9c44c81158b8850c85211a17a Mon Sep 17 00:00:00 2001 From: efim Date: Sat, 30 Jul 2022 18:33:04 +0000 Subject: [PATCH] buch of things to remind myself - characters are # and non-excape, #\a - i am way to quick to judge pairwise operations from left with #'reduce - iteration can be actually simple with dotimes, dolist. i'm quite afraid of #'loop but #'do seems cool and inviting --- lisp-koans/koans/iteration.lisp | 17 +++-- lisp-koans/koans/mapcar-and-reduce.lisp | 99 +++++++++++++++---------- lisp-koans/koans/strings.lisp | 54 +++++++------- lisp-koans/koans/structures.lisp | 50 ++++++------- 4 files changed, 121 insertions(+), 99 deletions(-) diff --git a/lisp-koans/koans/iteration.lisp b/lisp-koans/koans/iteration.lisp index 5268a3b..3330ed2 100644 --- a/lisp-koans/koans/iteration.lisp +++ b/lisp-koans/koans/iteration.lisp @@ -22,11 +22,12 @@ (dolist (number numbers) ;; (INCF PLACE N) is equivalent to (SETF PLACE (+ N PLACE)). (incf sum number)) - (assert-equal ____ sum)) + (assert-equal 108 sum)) ;; DOLIST can optionally return a value. (let ((sum 0)) - (assert-equal ____ (dolist (number numbers sum) + (assert-equal 108 (dolist (number numbers sum) (incf sum number)))))) +;; (apply #'+ '(4 8 15 16 23 42)) (define-test dotimes ;; The macro DOTIMES binds a variable to subsequent integers from 0 to @@ -34,10 +35,10 @@ (let ((stack '())) (dotimes (i 5) (push i stack)) - (assert-equal ____ stack)) + (assert-equal '(4 3 2 1 0) stack)) ;; DOTIMES can optionally return a value. (let ((stack '())) - (assert-equal ____ (dotimes (i 5 stack) + (assert-equal '(4 3 2 1 0) (dotimes (i 5 stack) (push i stack))))) (define-test do @@ -47,7 +48,7 @@ (do ((i 0 (1+ i))) ((> i 5)) (push i result)) - (assert-equal ____ result)) + (assert-equal '(5 4 3 2 1 0) result)) ;; The epilogue of DO can return a value. (let ((result (do ((i 0 (1+ i)) ;; A variable bound by DO noes not need to be updated on @@ -55,7 +56,7 @@ (result '())) ((> i 5) (nreverse result)) (push i result)))) - (assert-equal ____ result))) + (assert-equal '(0 1 2 3 4 5) result))) (define-test loop-basic-form ;; The macro LOOP in its simple form loops forever. It is possible to stop the @@ -64,10 +65,10 @@ (loop (incf counter) (when (>= counter 100) (return counter))) - (assert-equal ____ counter)) + (assert-equal 100 counter)) ;; The RETURN special form can return a value out of a LOOP. (let ((counter 0)) - (assert-equal ____ (loop (incf counter) + (assert-equal 100 (loop (incf counter) (when (>= counter 100) (return counter))))) ;; The extended form of LOOP will be contemplated in a future koan. diff --git a/lisp-koans/koans/mapcar-and-reduce.lisp b/lisp-koans/koans/mapcar-and-reduce.lisp index 76dfa83..901ec79 100644 --- a/lisp-koans/koans/mapcar-and-reduce.lisp +++ b/lisp-koans/koans/mapcar-and-reduce.lisp @@ -19,79 +19,96 @@ ;; Inside MAPCAR, he function 1+ will be applied to each element of NUMBERS. ;; A new list will be collected from the results. (assert-equal '(2 3 4 5 6 7) (mapcar #'1+ numbers)) - (assert-equal ____ (mapcar #'- numbers)) - (assert-equal ____ (mapcar #'list numbers)) - (assert-equal ____ (mapcar #'evenp numbers)) - (assert-equal ____ (mapcar #'numberp numbers)) - (assert-equal ____ (mapcar #'stringp numbers)) + (assert-equal '(-1 -2 -3 -4 -5 -6) (mapcar #'- numbers)) + (assert-equal '((1) (2) (3) (4) (5) (6)) (mapcar #'list numbers)) + (assert-equal '(nil t nil t nil t) (mapcar #'evenp numbers)) + (assert-equal '(t t t t t t) (mapcar #'numberp numbers)) + (assert-equal '(nil nil nil nil nil nil ) (mapcar #'stringp numbers)) ;; MAPCAR can work on multiple lists. The function will receive one argument ;; from each list. (let ((other-numbers '(4 8 15 16 23 42))) - (assert-equal ____ (mapcar #'+ numbers other-numbers)) - (assert-equal ____ (mapcar #'* numbers other-numbers)) + (assert-equal '(5 10 18 20 28 48) (mapcar #'+ numbers other-numbers)) + (assert-equal `(4 16 45 ,(* 16 4) ,(* 23 5) ,(* 42 6) ) (mapcar #'* numbers other-numbers)) ;; The function MOD performs modulo division. - (assert-equal ____ (mapcar #'mod other-numbers numbers))))) + (assert-equal `(0 0 0 0 3 0) (mapcar #'mod other-numbers numbers))))) (define-test mapcar-lambda ;; MAPCAR is often used with anonymous functions. (let ((numbers '(8 21 152 37 403 14 7 -34))) - (assert-equal ____ (mapcar (lambda (x) (mod x 10)) numbers))) + (assert-equal '(8 1 2 7 3 4 7 6) (mapcar (lambda (x) (mod x 10)) numbers))) (let ((strings '("Mary had a little lamb" "Old McDonald had a farm" "Happy birthday to you"))) - (assert-equal ____ (mapcar (lambda (x) (subseq x 4 12)) strings)))) + (assert-equal '(" had a l" "McDonald" "y birthd") (mapcar (lambda (x) (subseq x 4 12)) strings)))) (define-test map ;; MAP is a variant of MAPCAR that works on any sequences. ;; It allows to specify the type of the resulting sequence. (let ((string "lorem ipsum")) - (assert-equal ____ (map 'string #'char-upcase string)) - (assert-equal ____ (map 'list #'char-upcase string)) + (assert-equal "LOREM IPSUM" (map 'string #'char-upcase string)) + (assert-equal '(#\L #\O #\R #\E #\M #\ #\I #\P #\S #\U #\M) (map 'list #'char-upcase string)) ;; Not all vectors containing characters are strings. - (assert-equalp ____ (map '(vector t) #'char-upcase string)))) + (assert-equalp #(#\L #\O #\R #\E #\M #\ #\I #\P #\S #\U #\M) (map '(vector t) #'char-upcase string)))) +;; have no idea what's with the T + +(vector 1 2 3) +#(1 2 3 4) (define-test transposition - ;; MAPCAR gives the function as many arguments as there are lists. - (flet ((transpose (lists) (apply #'mapcar ____ lists))) - (let ((list '((1 2 3) - (4 5 6) - (7 8 9))) - (transposed-list '((1 4 7) - (2 5 8) - (3 6 9)))) - (assert-equal transposed-list (transpose list)) - (assert-equal ____ (transpose (transpose list)))) - (assert-equal ____ (transpose '(("these" "making") - ("pretzels" "me") - ("are" "thirsty")))))) + ;; MAPCAR gives the function as many arguments as there are lists. + (flet ((transpose (lists) (apply #'mapcar #'list lists))) + (let ((list '((1 2 3) + (4 5 6) + (7 8 9))) + (transposed-list '((1 4 7) + (2 5 8) + (3 6 9)))) + (assert-equal transposed-list (transpose list)) + (assert-equal list (transpose (transpose list)))) + (assert-equal '(("these" "pretzels" "are") + ("making" "me" "thirsty")) (transpose '(("these" "making") + ("pretzels" "me") + ("are" "thirsty")))))) + +(mapcar #'list (mapcar #'list '(1 2 3) '(11 22 33) '(111 222 333))) +;; welp, that wraps result in list +(defun my-transpose (&rest lists) + (apply #'mapcar #'list lists)) +(my-transpose (my-transpose '(1 2 3) '(11 22 33) '(111 222 333))) + +(defun my-transpose2 (lists) + (apply #'mapcar #'list lists)) +(my-transpose2 (my-transpose2 '((1 2 3) (11 22 33) (111 222 333)))) (define-test reduce - ;; The function REDUCE combines the elements of a list by applying a binary - ;; function to the elements of a sequence from left to right. - (assert-equal 15 (reduce #'+ '(1 2 3 4 5))) - (assert-equal ____ (reduce #'+ '(1 2 3 4))) - (assert-equal ____ (reduce #'expt '(1 2 3 4 5)))) + ;; The function REDUCE combines the elements of a list by applying a binary + ;; function to the elements of a sequence from left to right. + (assert-equal 15 (reduce #'+ '(1 2 3 4 5))) + (assert-equal 10 (reduce #'+ '(1 2 3 4))) + (assert-equal 1 (reduce #'expt '(1 2 3 4 5)))) + +(reduce #'expt '(1 2 3)) (define-test reduce-from-end - ;; The :FROM-END keyword argument can be used to reduce from right to left. - (let ((numbers '(1 2 3 4 5))) - (assert-equal ____ (reduce #'cons numbers)) - (assert-equal ____ (reduce #'cons numbers :from-end t))) + ;; The :FROM-END keyword argument can be used to reduce from right to left. + (let ((numbers '(1 2 3 4 5))) + (assert-equal '((((1 . 2) . 3) . 4) . 5) (reduce #'cons numbers)) ; and this I failed at first try + (assert-equal '(1 . (2 . (3 . (4 . 5)))) (reduce #'cons numbers :from-end t))) (let ((numbers '(2 3 2))) - (assert-equal ____ (reduce #'expt numbers)) - (assert-equal ____ (reduce #'expt numbers :from-end t)))) + (assert-equal (expt (expt 2 3) 2) (reduce #'expt numbers)) + (assert-equal (expt 2 9) (reduce #'expt numbers :from-end t)))) ; this I failed at first try (define-test reduce-initial-value ;; :INITIAL-VALUE can supply the initial value for the reduction. (let ((numbers '(1 2 3 4 5))) - (assert-equal ____ (reduce #'* numbers)) - (assert-equal ____ (reduce #'* numbers :initial-value 0)) - (assert-equal ____ (reduce #'* numbers :initial-value -1)))) + (assert-equal 120 (reduce #'* numbers)) + (assert-equal 0 (reduce #'* numbers :initial-value 0)) + (assert-equal -120 (reduce #'* numbers :initial-value -1)))) (define-test inner-product ;; MAPCAR and REDUCE are powerful when used together. ;; Fill in the blanks to produce a local function that computes an inner ;; product of two vectors. - (flet ((inner-product (x y) (reduce ____ (mapcar ____ x y)))) + (flet ((inner-product (x y) (reduce #'+ (mapcar #'* x y)))) (assert-equal 32 (inner-product '(1 2 3) '(4 5 6))) (assert-equal 310 (inner-product '(10 20 30) '(4 3 7))))) diff --git a/lisp-koans/koans/strings.lisp b/lisp-koans/koans/strings.lisp index dcf8850..7b33c2e 100644 --- a/lisp-koans/koans/strings.lisp +++ b/lisp-koans/koans/strings.lisp @@ -14,60 +14,64 @@ (define-test what-is-a-string (let ((string "Do, or do not. There is no try.")) - (true-or-false? ____ (typep string 'string)) + (true-or-false? t (typep string 'string)) ;; Strings are vectors of characters. - (true-or-false? ____ (typep string 'array)) - (true-or-false? ____ (typep string 'vector)) - (true-or-false? ____ (typep string '(vector character))) - (true-or-false? ____ (typep string 'integer)))) + (true-or-false? t (typep string 'array)) + (true-or-false? t (typep string 'vector)) + (true-or-false? t (typep string '(vector character))) + (true-or-false? nil (typep string 'integer)))) (define-test multiline-string ;; A Lisp string can span multiple lines. (let ((string "this is a multi line string")) - (true-or-false? ____ (typep string 'string)))) + (true-or-false? t (typep string 'string)))) (define-test escapes-in-strings ;; Quotes and backslashes in Lisp strings must be escaped. (let ((my-string "this string has one of these \" and a \\ in it")) - (true-or-false? ____ (typep my-string 'string)))) + (true-or-false? t (typep my-string 'string)))) + +(let ((my-string "this string has one of these \" and a \\ in it")) + (format t "~&unsescaped string ~S" my-string) + (format t "~&escaped string ~A" my-string)) ; yay, that's how I remember it from the book +;; printing escaped characters for pretty text output (define-test substrings - ;; Since strings are sequences, it is possible to use SUBSEQ on them. - (let ((string "Lorem ipsum dolor sit amet")) - (assert-equal ____ (subseq string 12)) - (assert-equal ____ (subseq string 6 11)) - (assert-equal ____ (subseq string 1 5)))) + ;; Since strings are sequences, it is possible to use SUBSEQ on them. + (let ((string "Lorem ipsum dolor sit amet")) + (assert-equal "dolor sit amet" (subseq string 12)) + (assert-equal "ipsum" (subseq string 6 11)) + (assert-equal "orem" (subseq string 1 5)))) (define-test strings-versus-characters ;; Strings and characters have distinct types. - (true-or-false? ____ (typep #\a 'character)) - (true-or-false? ____ (typep "A" 'character)) - (true-or-false? ____ (typep #\a 'string)) + (true-or-false? t (typep #\a 'character)) + (true-or-false? nil (typep "A" 'character)) + (true-or-false? nil (typep #\a 'string)) ;; One can use both AREF and CHAR to refer to characters in a string. (let ((my-string "Cookie Monster")) - (assert-equal ____ (char my-string 0)) - (assert-equal ____ (char my-string 3)) - (assert-equal ____ (aref my-string 7)))) + (assert-equal #\C (char my-string 0)) + (assert-equal #\k (char my-string 3)) + (assert-equal #\M (aref my-string 7)))) (define-test concatenating-strings ;; Concatenating strings in Common Lisp is possible, if a little cumbersome. (let ((a "Lorem") (b "ipsum") (c "dolor")) - (assert-equal ____ (concatenate 'string a " " b " " c)))) + (assert-equal "Lorem ipsum dolor" (concatenate 'string a " " b " " c)))) (define-test searching-for-characters ;; The function POSITION can be used to find the first position of an element ;; in a sequence. If the element is not found, NIL is returned. - (assert-equal ____ (position #\b "abc")) - (assert-equal ____ (position #\c "abc")) - (assert-equal ____ (position #\d "abc"))) + (assert-equal 1 (position #\b "abc")) + (assert-equal 2 (position #\c "abc")) + (assert-equal nil (position #\d "abc"))) (define-test finding-substrings ;; The function SEARCH can be used to search a sequence for subsequences. (let ((title "A supposedly fun thing I'll never do again")) - (assert-equal ____ (search "supposedly" title)) - (assert-equal 12 (search ____ title)))) - + (assert-equal 2 (search "supposedly" title)) + (assert-equal 12 (search " fun" title)))) diff --git a/lisp-koans/koans/structures.lisp b/lisp-koans/koans/structures.lisp index 42f88ef..ce969a9 100644 --- a/lisp-koans/koans/structures.lisp +++ b/lisp-koans/koans/structures.lisp @@ -30,12 +30,12 @@ (define-test make-struct (let ((player (make-basketball-player :name "Larry" :team :celtics :number 33))) - (true-or-false? ____ (basketball-player-p player)) - (assert-equal ____ (basketball-player-name player)) - (assert-equal ____ (basketball-player-team player)) - (assert-equal ____ (basketball-player-number player)) + (true-or-false? t (basketball-player-p player)) + (assert-equal "Larry" (basketball-player-name player)) + (assert-equal :celtics (basketball-player-team player)) + (assert-equal 33 (basketball-player-number player)) (setf (basketball-player-team player) :retired) - (assert-equal ____ (basketball-player-team player)))) + (assert-equal :retired (basketball-player-team player)))) ;;; Structure fields can have default values. @@ -46,8 +46,8 @@ (let ((player (make-baseball-player))) ;; We have not specified a default value for NAME, therefore we cannot ;; read it here - it would invoke undefined behaviour. - (assert-equal ____ (baseball-player-team player)) - (assert-equal ____ (baseball-player-position player)))) + (assert-equal :red-sox (baseball-player-team player)) + (assert-equal :outfield (baseball-player-position player)))) ;;; The accessor names can get pretty long. It's possible to specify a different ;;; prefix with the :CONC-NAME option. @@ -58,9 +58,9 @@ (define-test struct-access (let ((player (make-american-football-player :name "Drew Brees" :position :qb :team "Saints"))) - (assert-equal ____ (nfl-guy-name player)) - (assert-equal ____ (nfl-guy-team player)) - (assert-equal ____ (nfl-guy-position player)))) + (assert-equal "Drew Brees" (nfl-guy-name player)) + (assert-equal "Saints" (nfl-guy-team player)) + (assert-equal :qb (nfl-guy-position player)))) ;;; Structs can be defined to include other structure definitions. ;;; This form of inheritance allows composition of objects. @@ -73,14 +73,14 @@ :start-year 2004 :end-year 2011 :name "Kobe Bryant" :team :lakers :number 24))) - (assert-equal ____ (nba-contract-start-year contract)) - (assert-equal ____ (type-of contract)) + (assert-equal 2004 (nba-contract-start-year contract)) + (assert-equal 'nba-contract (type-of contract)) ;; Inherited structures follow the rules of type hierarchy. - (true-or-false? ____ (typep contract 'basketball-player)) + (true-or-false? t (typep contract 'basketball-player)) ;; One can access structure fields both with the structure's own accessors ;; and with the inherited accessors. - (assert-equal ____ (nba-contract-team contract)) - (assert-equal ____ (basketball-player-team contract)))) + (assert-equal :lakers (nba-contract-team contract)) + (assert-equal :lakers (basketball-player-team contract)))) ;;; Copying a structure named FOO is handled with the COPY-FOO function. ;;; All such copies are shallow. @@ -91,21 +91,21 @@ (manning-2 (make-american-football-player :name "Manning" :team (list "Colts" "Broncos")))) ;; MANNING-1 and MANNING-2 are different objects... - (true-or-false? ____ (eq manning-1 manning-2)) + (true-or-false? nil (eq manning-1 manning-2)) ;;...but they contain the same information. - (true-or-false? ____ (equalp manning-1 manning-2)) + (true-or-false? t (equalp manning-1 manning-2)) (let ((manning-3 (copy-american-football-player manning-1))) - (true-or-false? ____ (eq manning-1 manning-3)) - (true-or-false? ____ (equalp manning-1 manning-3)) + (true-or-false? nil (eq manning-1 manning-3)) + (true-or-false? t (equalp manning-1 manning-3)) ;; Setting the slot of one instance does not modify the others... (setf (nfl-guy-name manning-1) "Rogers") - (true-or-false? ____ (string= (nfl-guy-name manning-1) + (true-or-false? nil (string= (nfl-guy-name manning-1) (nfl-guy-name manning-3))) - (assert-equal ____ (nfl-guy-name manning-1)) - (assert-equal ____ (nfl-guy-name manning-3)) + (assert-equal "Rogers" (nfl-guy-name manning-1)) + (assert-equal "Manning" (nfl-guy-name manning-3)) ;; ...but modifying shared structure may affect other instances. (setf (car (nfl-guy-team manning-1)) "Giants") - (true-or-false? ____ (string= (car (nfl-guy-team manning-1)) + (true-or-false? t (string= (car (nfl-guy-team manning-1)) (car (nfl-guy-team manning-3)))) - (assert-equal ____ (car (nfl-guy-team manning-1))) - (assert-equal ____ (car (nfl-guy-team manning-3)))))) + (assert-equal "Giants" (car (nfl-guy-team manning-1))) + (assert-equal "Giants" (car (nfl-guy-team manning-3))))))