From 89673df8882c52436cf7c0a17012066037137c86 Mon Sep 17 00:00:00 2001 From: efim Date: Thu, 28 Jul 2022 15:35:14 +0000 Subject: [PATCH] new thing - functions returning multiple values (values 1 2 3) at the tnd of funtion fill make funciton return 1, 2, 3 and I can either treat function as returning single value, or use functions like multiple-value-list or multiple-value-[bind|setq] to get secodary return values so not quite like a tuple --- lisp-koans/koans/equality-distinctions.lisp | 102 +++++++++--------- lisp-koans/koans/hash-tables.lisp | 109 ++++++++++++-------- lisp-koans/koans/multiple-values.lisp | 24 +++-- 3 files changed, 131 insertions(+), 104 deletions(-) diff --git a/lisp-koans/koans/equality-distinctions.lisp b/lisp-koans/koans/equality-distinctions.lisp index 4bfb72a..950868c 100644 --- a/lisp-koans/koans/equality-distinctions.lisp +++ b/lisp-koans/koans/equality-distinctions.lisp @@ -20,45 +20,45 @@ ;; objects are, in fact, one and the same object. ;; It is the fastest of the four; however, not guaranteed to work on numbers ;; and characters because of that. - (true-or-false? ____ (eq 'a 'a)) - (true-or-false? ____ (eq 3 3.0)) - (true-or-false? ____ (eq '(1 2) '(1 2))) - (true-or-false? ____ (eq "Foo" "Foo")) - (true-or-false? ____ (eq "Foo" (copy-seq "Foo"))) - (true-or-false? ____ (eq "FOO" "Foo"))) + (true-or-false? t (eq 'a 'a)) + (true-or-false? nil (eq 3 3.0)) + (true-or-false? nil (eq '(1 2) '(1 2))) + (true-or-false? nil (eq "Foo" "Foo")) + (true-or-false? nil (eq "Foo" (copy-seq "Foo"))) + (true-or-false? nil (eq "FOO" "Foo"))) (define-test eql ;; EQL works like EQ, except it is specified to work for numbers and ;; characters. ;; Two numbers are EQL if they are of the same type and represent the same ;; number. Two characters are EQL if they represent the same character. - (true-or-false? ____ (eql 'a 'a)) - (true-or-false? ____ (eql 3 3)) - (true-or-false? ____ (eql 3 3.0)) - (true-or-false? ____ (eql '(1 2) '(1 2))) - (true-or-false? ____ (eql '(:a . :b) '(:a . :b))) - (true-or-false? ____ (eql #\S #\S)) - (true-or-false? ____ (eql "Foo" "Foo")) - (true-or-false? ____ (eql "Foo" (copy-seq "Foo"))) - (true-or-false? ____ (eql "FOO" "Foo"))) + (true-or-false? t (eql 'a 'a)) + (true-or-false? t (eql 3 3)) + (true-or-false? nil (eql 3 3.0)) + (true-or-false? nil (eql '(1 2) '(1 2))) + (true-or-false? nil (eql '(:a . :b) '(:a . :b))) + (true-or-false? t (eql #\S #\S)) + (true-or-false? nil (eql "Foo" "Foo")) + (true-or-false? nil (eql "Foo" (copy-seq "Foo"))) + (true-or-false? nil (eql "FOO" "Foo"))) (define-test equal ;; EQUAL works like EQL, except works differently for lists, strings, bit ;; vectors, and pathnames. ;; Two lists, strings, bit arrays, or pathnames are EQUAL if they have EQUAL ;; elements. - (true-or-false? ____ (equal 'a 'a)) - (true-or-false? ____ (equal 3 3)) - (true-or-false? ____ (equal 3 3.0)) - (true-or-false? ____ (equal '(1 2) '(1 2))) - (true-or-false? ____ (equal '(:a . :b) '(:a . :b))) - (true-or-false? ____ (equal '(:a . :b) '(:a . :doesnt-match))) - (true-or-false? ____ (equal #\S #\S)) - (true-or-false? ____ (equal "Foo" "Foo")) - (true-or-false? ____ (equal #*01010101 #*01010101)) - (true-or-false? ____ (equal "Foo" (copy-seq "Foo"))) - (true-or-false? ____ (equal "FOO" "Foo")) - (true-or-false? ____ (equal #p"foo/bar/baz" #p"foo/bar/baz"))) + (true-or-false? t (equal 'a 'a)) + (true-or-false? t (equal 3 3)) + (true-or-false? nil (equal 3 3.0)) ; this one I didn't get on first try. + (true-or-false? t (equal '(1 2) '(1 2))) + (true-or-false? t (equal '(:a . :b) '(:a . :b))) + (true-or-false? nil (equal '(:a . :b) '(:a . :doesnt-match))) + (true-or-false? t (equal #\S #\S)) + (true-or-false? t (equal "Foo" "Foo")) + (true-or-false? t (equal #*01010101 #*01010101)) + (true-or-false? t (equal "Foo" (copy-seq "Foo"))) + (true-or-false? nil (equal "FOO" "Foo")) + (true-or-false? t (equal #p"foo/bar/baz" #p"foo/bar/baz"))) (defstruct thing slot-1 slot-2) @@ -74,19 +74,19 @@ ;; Two structures are EQUALP if they are of the same class and their slots are ;; pairwise EQUALP. ;; We will contemplate hash tables in the HASH-TABLES lesson. - (true-or-false? ____ (equalp 'a 'a)) - (true-or-false? ____ (equalp 3 3)) - (true-or-false? ____ (equalp 3 3.0)) - (true-or-false? ____ (equalp '(1 2) '(1 2))) - (true-or-false? ____ (equalp '(:a . :b) '(:a . :b))) - (true-or-false? ____ (equalp '(:a . :b) '(:a . :doesnt-match))) - (true-or-false? ____ (equalp #\S #\S)) - (true-or-false? ____ (equalp "Foo" "Foo")) - (true-or-false? ____ (equalp "Foo" (copy-seq "Foo"))) - (true-or-false? ____ (equalp "FOO" "Foo")) - (true-or-false? ____ (equalp (make-array '(4 2) :initial-element 0) + (true-or-false? t (equalp 'a 'a)) + (true-or-false? t (equalp 3 3)) + (true-or-false? t (equalp 3 3.0)) + (true-or-false? t (equalp '(1 2) '(1 2))) + (true-or-false? t (equalp '(:a . :b) '(:a . :b))) + (true-or-false? nil (equalp '(:a . :b) '(:a . :doesnt-match))) + (true-or-false? t (equalp #\S #\S)) + (true-or-false? t (equalp "Foo" "Foo")) + (true-or-false? t (equalp "Foo" (copy-seq "Foo"))) + (true-or-false? t (equalp "FOO" "Foo")) ; this one didn't get on first try + (true-or-false? t (equalp (make-array '(4 2) :initial-element 0) (make-array '(4 2) :initial-element 0))) - (true-or-false? ____ (equalp (make-thing :slot-1 42 :slot-2 :forty-two) + (true-or-false? t (equalp (make-thing :slot-1 42 :slot-2 :forty-two) (make-thing :slot-1 42 :slot-2 :forty-two)))) ;;; In additional to the generic equality predicates, Lisp also provides @@ -95,27 +95,27 @@ (define-test = ;; The function = behaves just like EQUALP on numbers. ;; #C(... ...) is syntax sugar for creating a complex number. - (true-or-false? ____ (= 99.0 99 99.000 #C(99 0) #C(99.0 0.0))) - (true-or-false? ____ (= 0 1 -1)) - (true-or-false? ____ (= (/ 2 3) (/ 6 9) (/ 86 129)))) + (true-or-false? t (= 99.0 99 99.000 #C(99 0) #C(99.0 0.0))) + (true-or-false? nil (= 0 1 -1)) + (true-or-false? t (= (/ 2 3) (/ 6 9) (/ 86 129)))) (define-test string= ;; The function STRING= behaves just like EQUAL on strings. ;; The function STRING-EQUAL behaves just like EQUALP on strings. - (true-or-false? ____ (string= "Foo" "Foo")) - (true-or-false? ____ (string= "Foo" "FOO")) - (true-or-false? ____ (string-equal "Foo" "FOO")) + (true-or-false? t (string= "Foo" "Foo")) + (true-or-false? nil (string= "Foo" "FOO")) + (true-or-false? t (string-equal "Foo" "FOO")) ;; These functions accept additional keyword arguments that allow one to ;; only compare parts of the strings. - (true-or-false? ____ (string= "together" "frog" :start1 1 :end1 3 + (true-or-false? t (string= "together" "frog" :start1 1 :end1 3 :start2 2)) - (true-or-false? ____ (string-equal "together" "FROG" :start1 1 :end1 3 + (true-or-false? t (string-equal "together" "FROG" :start1 1 :end1 3 :start2 2))) (define-test char= ;; The function CHAR= behaves just like EQL on characters. ;; The function CHAR-EQUAL behaves just like EQUALP on characters. - (true-or-false? ____ (char= #\A (char "ABCDEF" 0))) - (true-or-false? ____ (char= #\A #\a)) - (true-or-false? ____ (char-equal #\A (char "ABCDEF" 0))) - (true-or-false? ____ (char-equal #\A #\a))) + (true-or-false? t (char= #\A (char "ABCDEF" 0))) + (true-or-false? nil (char= #\A #\a)) + (true-or-false? t (char-equal #\A (char "ABCDEF" 0))) + (true-or-false? t (char-equal #\A #\a))) diff --git a/lisp-koans/koans/hash-tables.lisp b/lisp-koans/koans/hash-tables.lisp index 35ffb5e..7efc143 100644 --- a/lisp-koans/koans/hash-tables.lisp +++ b/lisp-koans/koans/hash-tables.lisp @@ -16,69 +16,88 @@ (define-test make-hash-table (let ((my-hash-table (make-hash-table))) - (true-or-false? ____ (typep my-hash-table 'hash-table)) - (true-or-false? ____ (hash-table-p my-hash-table)) - (true-or-false? ____ (hash-table-p (make-array '(3 3 3)))) + (true-or-false? t (typep my-hash-table 'hash-table)) + (true-or-false? t (hash-table-p my-hash-table)) + (true-or-false? nil (hash-table-p (make-array '(3 3 3)))) ;; The function HASH-TABLE-COUNT returns the number of entries currently ;; contained in a hash table. - (assert-equal ____ (hash-table-count my-hash-table)))) + (assert-equal 0 (hash-table-count my-hash-table)))) (define-test gethash ;; The function GETHASH can be used to access hash table values. (let ((cube-roots (make-hash-table))) ;; We add the key-value pair 1 - "uno" to the hash table. (setf (gethash 1 cube-roots) "uno") - (assert-equal ____ (gethash 1 cube-roots)) - (assert-equal ____ (hash-table-count cube-roots)) + (assert-equal "uno" (gethash 1 cube-roots)) + (assert-equal 1 (hash-table-count cube-roots)) (setf (gethash 8 cube-roots) 2) (setf (gethash -3 cube-roots) -27) - (assert-equal ____ (gethash -3 cube-roots)) - (assert-equal ____ (hash-table-count cube-roots)) + (assert-equal -27 (gethash -3 cube-roots)) + (assert-equal 3 (hash-table-count cube-roots)) ;; GETHASH returns a secondary value that is true if the key was found in ;; the hash-table and false otherwise. (multiple-value-bind (value foundp) (gethash 8 cube-roots) - (assert-equal ____ value) - (assert-equal ____ foundp)) + (assert-equal 2 value) + (assert-equal t foundp)) (multiple-value-bind (value foundp) (gethash 125 cube-roots) - (assert-equal ____ value) - (assert-equal ____ foundp)))) + (assert-equal nil value) + (assert-equal nil foundp)))) + +(let ((my-hash (make-hash-table))) + (setf (gethash 1 my-hash) "lala-one") + (setq inner-value (gethash 1 my-hash)) + (multiple-value-setq (inner-value-tuple containment-mark) (gethash 2 my-hash)) + (format t "~&get hash is ~S, and variable ~S" (gethash 1 my-hash) inner-value) + (format t "~&and multi-value-setq gets ~S and ~S for key 2" inner-value-tuple containment-mark)) +;; so format, gets first value +;; I guess that assigning to some variable, would also just discard second value +;; if i dont' want it? +;; +;; cool (define-test hash-table-test - ;; A hash table can be constructed with different test predicates. - ;; The programmer may choose between EQ, EQL, EQUAL, and EQUALP to get the - ;; best performance and expected results from the hash table. - ;; The default test predicate is EQL. - (let ((eq-table (make-hash-table :test #'eq)) - (eql-table (make-hash-table)) - (equal-table (make-hash-table :test #'equal)) - (equalp-table (make-hash-table :test #'equalp))) - ;; We will define four variables whose values are strings. - (let* ((string "one") - (same-string string) - (string-copy (copy-seq string)) - (string-upcased "ONE")) - ;; We will insert the value of each variable into each hash table. - (dolist (thing (list string same-string string-copy string-upcased)) - (dolist (hash-table (list eq-table eql-table equal-table equalp-table)) - (setf (gethash thing hash-table) t)))) - ;; How many entries does each hash table contain? - (assert-equal ____ (hash-table-count eq-table)) - (assert-equal ____ (hash-table-count eql-table)) - (assert-equal ____ (hash-table-count equal-table)) - (assert-equal ____ (hash-table-count equalp-table)))) + ;; A hash table can be constructed with different test predicates. + ;; The programmer may choose between EQ, EQL, EQUAL, and EQUALP to get the + ;; best performance and expected results from the hash table. + ;; The default test predicate is EQL. + (let ((eq-table (make-hash-table :test #'eq)) + (eql-table (make-hash-table)) + (equal-table (make-hash-table :test #'equal)) + (equalp-table (make-hash-table :test #'equalp))) + ;; We will define four variables whose values are strings. + (let* ((string "one") + (same-string string) + (string-copy (copy-seq string)) + (string-upcased "ONE")) + ;; We will insert the value of each variable into each hash table. + (dolist (thing (list string same-string string-copy string-upcased)) + (dolist (hash-table (list eq-table eql-table equal-table equalp-table)) + (setf (gethash thing hash-table) t)))) + ;; How many entries does each hash table contain? + (assert-equal 3 (hash-table-count eq-table)) + (assert-equal 3 (hash-table-count eql-table)) ; didn't get that on first try + ;; i guess eql still not compares strings + (assert-equal 2 (hash-table-count equal-table)) + (assert-equal 1 (hash-table-count equalp-table)))) +(eql "hello" "hello") ; yup (define-test hash-table-equality - ;; EQUALP considers two hash tables to be equal if they have the same test and - ;; if its key-value pairs are the same under that test. - (let ((hash-table-1 (make-hash-table :test #'equal)) - (hash-table-2 (make-hash-table :test #'equal))) - (setf (gethash "one" hash-table-1) "yat") - (setf (gethash "one" hash-table-2) "yat") - (setf (gethash "two" hash-table-1) "yi") - (setf (gethash "two" hash-table-2) "yi") - (true-or-false? ____ (eq hash-table-1 hash-table-2)) - (true-or-false? ____ (equal hash-table-1 hash-table-2)) - (true-or-false? ____ (equalp hash-table-1 hash-table-2)))) + ;; EQUALP considers two hash tables to be equal if they have the same test and + ;; if its key-value pairs are the same under that test. + (let ((hash-table-1 (make-hash-table :test #'equal)) + (hash-table-2 (make-hash-table :test #'equal))) + (setf (gethash "one" hash-table-1) "yat") + (setf (gethash "one" hash-table-2) "yat") + (setf (gethash "two" hash-table-1) "yi") + (setf (gethash "two" hash-table-2) "yi") + (true-or-false? nil (eq hash-table-1 hash-table-2)) + (true-or-false? nil (equal hash-table-1 hash-table-2)) + (true-or-false? t (equalp hash-table-1 hash-table-2)))) + +;; I guess after that I want to reread difference between equal and equalp =C +;; structures EQUAL if their elements EQUAL, same with EQUALP +;; but differnt strings are not EQUAL, cool +(equal "string1" "string1") (define-test i-will-make-it-equalp ;; Disabled on ECL due to a conformance bug. diff --git a/lisp-koans/koans/multiple-values.lisp b/lisp-koans/koans/multiple-values.lisp index 5459c0a..2ec9540 100644 --- a/lisp-koans/koans/multiple-values.lisp +++ b/lisp-koans/koans/multiple-values.lisp @@ -22,20 +22,28 @@ (y (multiple-value-list (floor 3/2)))) (assert-equal x 1) (assert-equal y '(1 1/2))) - (assert-equal ____ (multiple-value-list (floor 99/4)))) + (assert-equal '(24 3/4) (multiple-value-list (floor 99/4)))) (defun next-fib (a b) ;; The function VALUES allows returning multiple values. (values b (+ a b))) +(values 5 4 3) ; now this, is very new and like what +;; not at all what I saw in scala types, if that's not a tuple, but just "multiple values" + +;; funcitons are with prefix #'multiple-values-.* + (define-test binding-and-setting-multiple-values - ;; The macro MULTIPLE-VALUE-BIND is like LET, except it binds the variables - ;; listed in its first argument to the values returned by the form that is its - ;; second argument. - (multiple-value-bind (x y) (next-fib 3 5) - (let ((result (* x y))) - (assert-equal ____ result))) + ;; The macro MULTIPLE-VALUE-BIND is like LET, except it binds the variables + ;; listed in its first argument to the values returned by the form that is its + ;; second argument. + (multiple-value-bind (x y) (next-fib 3 5) + (let ((result (* x y))) + (assert-equal 40 result))) ;; SETF can also set multiple values if a VALUES form is provided as a place. (let (x y) (setf (values x y) (next-fib 5 8)) - (assert-equal ____ (list x y)))) + (assert-equal '(8 13) (list x y)))) + +;;; or maybe #'values is a tuple, +;;; it's used as accessor in setf, not quite destructuring, since that's not possible with lists?