From b7bccb9cfbad642f860945cc93052af0cf54ba3b Mon Sep 17 00:00:00 2001 From: efim Date: Wed, 3 Aug 2022 20:43:31 +0000 Subject: [PATCH] koans on types and clos - types are complicated, not sure how to look up documentation for it would they show up in apropos all? - list formatted types - like array vector can specify type of element, rank / dimentions (not sure there's variancy over the element type?) - clos - similar to structure for structured you get separate functions to get slots, use setf to set generalized variables with classes, I can use generic function to create #'make-instance and access slots with (#'slot-value instance 'slot-name) but there could be defined accessor, reader, writer, and :initarg to name slot to have handle to set value in constructor now that's a lot --- lisp-koans/koans/clos.lisp | 54 +++++++---- lisp-koans/koans/type-checking.lisp | 144 ++++++++++++++-------------- 2 files changed, 110 insertions(+), 88 deletions(-) diff --git a/lisp-koans/koans/clos.lisp b/lisp-koans/koans/clos.lisp index 44822d6..f560883 100644 --- a/lisp-koans/koans/clos.lisp +++ b/lisp-koans/koans/clos.lisp @@ -18,17 +18,25 @@ ;; A class definition lists all the slots of every instance. (color speed)) +;; what's the difference with defstruct? +(defstruct struct-racecar + color speed) +(setq my-struct-racecar (make-struct-racecar :color :red :speed 45)) +(struct-racecar-color my-struct-racecar) + +;; they have generic setters and accessort, ok (define-test defclass - ;; Class instances are constructed via MAKE-INSTANCE. - (let ((car-1 (make-instance 'racecar)) - (car-2 (make-instance 'racecar))) - ;; Slot values can be set via SLOT-VALUE. - (setf (slot-value car-1 'color) :red) - (setf (slot-value car-1 'speed) 220) - (setf (slot-value car-2 'color) :blue) - (setf (slot-value car-2 'speed) 240) - (assert-equal ____ (slot-value car-1 'color)) - (assert-equal ____ (slot-value car-2 'speed)))) + ;; Class instances are constructed via MAKE-INSTANCE. + (let ((car-1 (make-instance 'racecar)) + (car-2 (make-instance 'racecar))) + ;; Slot values can be set via SLOT-VALUE. + (setf (slot-value car-1 'color) :red) + (setf (slot-value car-1 'speed) 220) + (setf (slot-value car-2 'color) :blue) + (setf (slot-value car-2 'speed) 240) + (assert-equal :red (slot-value car-1 'color)) + (assert-equal 240 (slot-value car-2 'speed)))) +;; so, using #'slot-value and #'make-instance ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -44,18 +52,28 @@ ((color :reader color :writer (setf color)) (speed :accessor speed))) +(setq my-ship (make-instance 'spaceship)) +(setf (color my-ship) :green) +(color my-ship) + ;;; Specifying a reader function named COLOR is equivalent to ;;; (DEFMETHOD COLOR ((OBJECT SPACECSHIP)) ...) ;;; Specifying a writer function named (SETF COLOR) is equivalent to ;;; (DEFMETHOD (SETF COLOR) (NEW-VALUE (OBJECT SPACECSHIP)) ...) ;;; Specifying an accessor function performs both of the above. +;; I don't understand what (defmethod (setf color) ...) means +;; is that two atom name? wtf +;; nope - function-name::= {symbol | (setf symbol)} +;; http://www.lispworks.com/documentation/HyperSpec/Body/m_defmet.htm +;; still not quite understand it, lots of complicated things, about different forms + (define-test accessors - (let ((ship (make-instance 'spaceship))) - (setf (color ship) :orange - (speed ship) 1000) - (assert-equal ____ (color ship)) - (assert-equal ____ (speed ship)))) + (let ((ship (make-instance 'spaceship))) + (setf (color ship) :orange + (speed ship) 1000) + (assert-equal :orange (color ship)) + (assert-equal 1000 (speed ship)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -66,8 +84,10 @@ (define-test initargs (let ((bike (make-instance 'bike :color :blue :speed 30))) - (assert-equal ____ (color bike)) - (assert-equal ____ (speed bike)))) + (assert-equal :blue (color bike)) + (assert-equal 30 (speed bike)))) +;; oh, so that's for defining initial values in the constructor +;; i guess ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/lisp-koans/koans/type-checking.lisp b/lisp-koans/koans/type-checking.lisp index 09a3b14..39bcce8 100644 --- a/lisp-koans/koans/type-checking.lisp +++ b/lisp-koans/koans/type-checking.lisp @@ -18,30 +18,30 @@ (define-test typep ;; TYPEP returns true if the provided object is of the provided type. - (true-or-false? ____ (typep "hello" 'string)) - (true-or-false? ____ (typep "hello" 'array)) - (true-or-false? ____ (typep "hello" 'list)) - (true-or-false? ____ (typep "hello" '(simple-array character (5)))) - (true-or-false? ____ (typep '(1 2 3) 'list)) - (true-or-false? ____ (typep 99 'integer)) - (true-or-false? ____ (typep nil 'NULL)) - (true-or-false? ____ (typep 22/7 'ratio)) - (true-or-false? ____ (typep 4.0 'float)) - (true-or-false? ____ (typep #\a 'character)) - (true-or-false? ____ (typep #'length 'function))) + (true-or-false? t (typep "hello" 'string)) + (true-or-false? t (typep "hello" 'array)) + (true-or-false? nil (typep "hello" 'list)) + (true-or-false? t (typep "hello" '(simple-array character (5)))) + (true-or-false? t (typep '(1 2 3) 'list)) + (true-or-false? t (typep 99 'integer)) + (true-or-false? t (typep nil 'NULL)) + (true-or-false? t (typep 22/7 'ratio)) + (true-or-false? t (typep 4.0 'float)) + (true-or-false? t (typep #\a 'character)) + (true-or-false? t (typep #'length 'function))) (define-test type-of ;; TYPE-OF returns a type specifier for the object. - (assert-equal ____ (type-of '())) - (assert-equal ____ (type-of 4/6))) + (assert-equal 'NULL (type-of '())) + (assert-equal 'ratio (type-of 4/6))) (define-test overlapping-types ;; Because Lisp types are mathematical sets, they are allowed to overlap. (let ((thing '())) - (true-or-false? ____ (typep thing 'list)) - (true-or-false? ____ (typep thing 'atom)) - (true-or-false? ____ (typep thing 'null)) - (true-or-false? ____ (typep thing 't)))) + (true-or-false? t (typep thing 'list)) + (true-or-false? t (typep thing 'atom)) + (true-or-false? t (typep thing 'null)) + (true-or-false? t (typep thing 't)))) (define-test fixnum-versus-bignum ;; In Lisp, integers are either fixnums or bignums. Fixnums are handled more @@ -54,20 +54,20 @@ (integer-2 most-positive-fixnum) (integer-3 (1+ most-positive-fixnum)) (integer-4 (1- most-negative-fixnum))) - (true-or-false? ____ (typep integer-1 'fixnum)) - (true-or-false? ____ (typep integer-1 'bignum)) - (true-or-false? ____ (typep integer-2 'fixnum)) - (true-or-false? ____ (typep integer-2 'bignum)) - (true-or-false? ____ (typep integer-3 'fixnum)) - (true-or-false? ____ (typep integer-3 'bignum)) - (true-or-false? ____ (typep integer-4 'fixnum)) - (true-or-false? ____ (typep integer-4 'bignum)) + (true-or-false? t (typep integer-1 'fixnum)) + (true-or-false? nil (typep integer-1 'bignum)) + (true-or-false? t (typep integer-2 'fixnum)) + (true-or-false? nil (typep integer-2 'bignum)) + (true-or-false? nil (typep integer-3 'fixnum)) + (true-or-false? t (typep integer-3 'bignum)) + (true-or-false? nil (typep integer-4 'fixnum)) + (true-or-false? t (typep integer-4 'bignum)) ;; Regardless of whether an integer is a fixnum or a bignum, it is still ;; an integer. - (true-or-false? ____ (typep integer-1 'integer)) - (true-or-false? ____ (typep integer-2 'integer)) - (true-or-false? ____ (typep integer-3 'integer)) - (true-or-false? ____ (typep integer-4 'integer)))) + (true-or-false? t (typep integer-1 'integer)) + (true-or-false? t (typep integer-2 'integer)) + (true-or-false? t (typep integer-3 'integer)) + (true-or-false? t (typep integer-4 'integer)))) (define-test subtypep (assert-true (typep 1 'bit)) @@ -76,10 +76,10 @@ (assert-true (typep 2 'integer)) ;; The function SUBTYPEP attempts to answer whether one type specifier ;; represents a subtype of the other type specifier. - (true-or-false? ____ (subtypep 'bit 'integer)) - (true-or-false? ____ (subtypep 'vector 'array)) - (true-or-false? ____ (subtypep 'string 'vector)) - (true-or-false? ____ (subtypep 'null 'list))) + (true-or-false? t (subtypep 'bit 'integer)) + (true-or-false? t (subtypep 'vector 'array)) + (true-or-false? t (subtypep 'string 'vector)) + (true-or-false? t (subtypep 'null 'list))) (define-test list-type-specifiers ;; Some type specifiers are lists; this way, they carry more information than @@ -88,64 +88,66 @@ (assert-true (typep (make-array 42) '(vector * 42))) (assert-true (typep (make-array 42 :element-type 'bit) '(vector bit 42))) (assert-true (typep (make-array '(4 2)) '(array * (4 2)))) - (true-or-false? ____ (typep (make-array '(3 3)) '(simple-array t (3 3)))) - (true-or-false? ____ (typep (make-array '(3 2 1)) '(simple-array t (1 2 3))))) + (true-or-false? t (typep (make-array '(3 3)) '(simple-array t (3 3)))) + (true-or-false? nil (typep (make-array '(3 2 1)) '(simple-array t (1 2 3))))) (define-test list-type-specifiers-hierarchy ;; Type specifiers that are lists also follow hierarchy. - (true-or-false? ____ (subtypep '(simple-array t (3 3)) '(simple-array t *))) - (true-or-false? ____ (subtypep '(vector double-float 100) '(vector * 100))) - (true-or-false? ____ (subtypep '(vector double-float 100) '(vector double-float *))) - (true-or-false? ____ (subtypep '(vector double-float 100) '(vector * *))) - (true-or-false? ____ (subtypep '(vector double-float 100) '(array * *))) - (true-or-false? ____ (subtypep '(vector double-float 100) t))) + (true-or-false? t (subtypep '(simple-array t (3 3)) '(simple-array t *))) + (true-or-false? t (subtypep '(vector double-float 100) '(vector * 100))) + (true-or-false? t (subtypep '(vector double-float 100) '(vector double-float *))) + (true-or-false? t (subtypep '(vector double-float 100) '(vector * *))) + (true-or-false? t (subtypep '(vector double-float 100) '(array * *))) + (true-or-false? t (subtypep '(vector double-float 100) t))) (define-test type-coercion (assert-true (typep 0 'integer)) - (true-or-false? ____ (typep 0 'short-float)) - (true-or-false? ____ (subtypep 'integer 'short-float)) - (true-or-false? ____ (subtypep 'short-float 'integer)) + (true-or-false? nil (typep 0 'short-float)) + (true-or-false? nil (subtypep 'integer 'short-float)) + (true-or-false? nil (subtypep 'short-float 'integer)) ;; The function COERCE makes it possible to convert values between some ;; standard types. - (true-or-false? ____ (typep (coerce 0 'short-float) 'short-float))) + (true-or-false? t (typep (coerce 0 'short-float) 'short-float))) (define-test atoms-are-anything-thats-not-a-cons ;; In Lisp, an atom is anything that is not a cons cell. The function ATOM ;; returns true if its object is an atom. - (true-or-false? ____ (atom 4)) - (true-or-false? ____ (atom '(1 2 3 4))) - (true-or-false? ____ (atom '(:foo . :bar))) - (true-or-false? ____ (atom 'symbol)) - (true-or-false? ____ (atom :keyword)) - (true-or-false? ____ (atom #(1 2 3 4 5))) - (true-or-false? ____ (atom #\A)) - (true-or-false? ____ (atom "string")) - (true-or-false? ____ (atom (make-array '(4 4))))) + (true-or-false? t (atom 4)) + (true-or-false? nil (atom '(1 2 3 4))) + (true-or-false? nil (atom '(:foo . :bar))) + (true-or-false? t (atom 'symbol)) + (true-or-false? t (atom :keyword)) + (true-or-false? t (atom #(1 2 3 4 5))) + (true-or-false? t (atom #\A)) + (true-or-false? t (atom "string")) + (true-or-false? t (atom (make-array '(4 4))))) (define-test functionp - ;; The function FUNCTIONP returns true if its arguments is a function. - (assert-true (functionp (lambda (a b c) (+ a b c)))) - (true-or-false? ____ (functionp #'make-array)) - (true-or-false? ____ (functionp 'make-array)) - (true-or-false? ____ (functionp (lambda (x) (* x x)))) - (true-or-false? ____ (functionp '(lambda (x) (* x x)))) - (true-or-false? ____ (functionp '(1 2 3))) - (true-or-false? ____ (functionp t))) + ;; The function FUNCTIONP returns true if its arguments is a function. + (assert-true (functionp (lambda (a b c) (+ a b c)))) + (true-or-false? t (functionp #'make-array)) + (true-or-false? nil (functionp 'make-array)) ; I didn't get this one, looks like that's not function + ; how's that in Elisp though? + ; in Elisp both #' and ' over function is a function, cool + (true-or-false? t (functionp (lambda (x) (* x x)))) + (true-or-false? nil (functionp '(lambda (x) (* x x)))) + (true-or-false? nil (functionp '(1 2 3))) + (true-or-false? nil (functionp t))) (define-test other-type-predicates ;; Lisp defines multiple type predicates for standard types.. - (true-or-false? ____ (numberp 999)) - (true-or-false? ____ (listp '(9 9 9))) - (true-or-false? ____ (integerp 999)) - (true-or-false? ____ (rationalp 9/99)) - (true-or-false? ____ (floatp 9.99)) - (true-or-false? ____ (stringp "nine nine nine")) - (true-or-false? ____ (characterp #\9)) - (true-or-false? ____ (bit-vector-p #*01001))) + (true-or-false? t (numberp 999)) + (true-or-false? t (listp '(9 9 9))) + (true-or-false? t (integerp 999)) + (true-or-false? t (rationalp 9/99)) + (true-or-false? t (floatp 9.99)) + (true-or-false? t (stringp "nine nine nine")) + (true-or-false? t (characterp #\9)) + (true-or-false? t (bit-vector-p #*01001))) (define-test guess-that-type ;; Fill in the blank with a type specifier that satisfies the following tests. - (let ((type ____)) + (let ((type '(simple-array array (5 3 *)))) ; this needs reallife context for me to get (assert-true (subtypep type '(simple-array * (* 3 *)))) (assert-true (subtypep type '(simple-array * (5 * *)))) (assert-true (subtypep type '(simple-array array *)))