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
This commit is contained in:
efim 2022-07-28 15:35:14 +00:00
parent 6dcca61283
commit 89673df888
3 changed files with 131 additions and 104 deletions

View File

@ -20,45 +20,45 @@
;; objects are, in fact, one and the same object. ;; objects are, in fact, one and the same object.
;; It is the fastest of the four; however, not guaranteed to work on numbers ;; It is the fastest of the four; however, not guaranteed to work on numbers
;; and characters because of that. ;; and characters because of that.
(true-or-false? ____ (eq 'a 'a)) (true-or-false? t (eq 'a 'a))
(true-or-false? ____ (eq 3 3.0)) (true-or-false? nil (eq 3 3.0))
(true-or-false? ____ (eq '(1 2) '(1 2))) (true-or-false? nil (eq '(1 2) '(1 2)))
(true-or-false? ____ (eq "Foo" "Foo")) (true-or-false? nil (eq "Foo" "Foo"))
(true-or-false? ____ (eq "Foo" (copy-seq "Foo"))) (true-or-false? nil (eq "Foo" (copy-seq "Foo")))
(true-or-false? ____ (eq "FOO" "Foo"))) (true-or-false? nil (eq "FOO" "Foo")))
(define-test eql (define-test eql
;; EQL works like EQ, except it is specified to work for numbers and ;; EQL works like EQ, except it is specified to work for numbers and
;; characters. ;; characters.
;; Two numbers are EQL if they are of the same type and represent the same ;; 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. ;; number. Two characters are EQL if they represent the same character.
(true-or-false? ____ (eql 'a 'a)) (true-or-false? t (eql 'a 'a))
(true-or-false? ____ (eql 3 3)) (true-or-false? t (eql 3 3))
(true-or-false? ____ (eql 3 3.0)) (true-or-false? nil (eql 3 3.0))
(true-or-false? ____ (eql '(1 2) '(1 2))) (true-or-false? nil (eql '(1 2) '(1 2)))
(true-or-false? ____ (eql '(:a . :b) '(:a . :b))) (true-or-false? nil (eql '(:a . :b) '(:a . :b)))
(true-or-false? ____ (eql #\S #\S)) (true-or-false? t (eql #\S #\S))
(true-or-false? ____ (eql "Foo" "Foo")) (true-or-false? nil (eql "Foo" "Foo"))
(true-or-false? ____ (eql "Foo" (copy-seq "Foo"))) (true-or-false? nil (eql "Foo" (copy-seq "Foo")))
(true-or-false? ____ (eql "FOO" "Foo"))) (true-or-false? nil (eql "FOO" "Foo")))
(define-test equal (define-test equal
;; EQUAL works like EQL, except works differently for lists, strings, bit ;; EQUAL works like EQL, except works differently for lists, strings, bit
;; vectors, and pathnames. ;; vectors, and pathnames.
;; Two lists, strings, bit arrays, or pathnames are EQUAL if they have EQUAL ;; Two lists, strings, bit arrays, or pathnames are EQUAL if they have EQUAL
;; elements. ;; elements.
(true-or-false? ____ (equal 'a 'a)) (true-or-false? t (equal 'a 'a))
(true-or-false? ____ (equal 3 3)) (true-or-false? t (equal 3 3))
(true-or-false? ____ (equal 3 3.0)) (true-or-false? nil (equal 3 3.0)) ; this one I didn't get on first try.
(true-or-false? ____ (equal '(1 2) '(1 2))) (true-or-false? t (equal '(1 2) '(1 2)))
(true-or-false? ____ (equal '(:a . :b) '(:a . :b))) (true-or-false? t (equal '(:a . :b) '(:a . :b)))
(true-or-false? ____ (equal '(:a . :b) '(:a . :doesnt-match))) (true-or-false? nil (equal '(:a . :b) '(:a . :doesnt-match)))
(true-or-false? ____ (equal #\S #\S)) (true-or-false? t (equal #\S #\S))
(true-or-false? ____ (equal "Foo" "Foo")) (true-or-false? t (equal "Foo" "Foo"))
(true-or-false? ____ (equal #*01010101 #*01010101)) (true-or-false? t (equal #*01010101 #*01010101))
(true-or-false? ____ (equal "Foo" (copy-seq "Foo"))) (true-or-false? t (equal "Foo" (copy-seq "Foo")))
(true-or-false? ____ (equal "FOO" "Foo")) (true-or-false? nil (equal "FOO" "Foo"))
(true-or-false? ____ (equal #p"foo/bar/baz" #p"foo/bar/baz"))) (true-or-false? t (equal #p"foo/bar/baz" #p"foo/bar/baz")))
(defstruct thing slot-1 slot-2) (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 ;; Two structures are EQUALP if they are of the same class and their slots are
;; pairwise EQUALP. ;; pairwise EQUALP.
;; We will contemplate hash tables in the HASH-TABLES lesson. ;; We will contemplate hash tables in the HASH-TABLES lesson.
(true-or-false? ____ (equalp 'a 'a)) (true-or-false? t (equalp 'a 'a))
(true-or-false? ____ (equalp 3 3)) (true-or-false? t (equalp 3 3))
(true-or-false? ____ (equalp 3 3.0)) (true-or-false? t (equalp 3 3.0))
(true-or-false? ____ (equalp '(1 2) '(1 2))) (true-or-false? t (equalp '(1 2) '(1 2)))
(true-or-false? ____ (equalp '(:a . :b) '(:a . :b))) (true-or-false? t (equalp '(:a . :b) '(:a . :b)))
(true-or-false? ____ (equalp '(:a . :b) '(:a . :doesnt-match))) (true-or-false? nil (equalp '(:a . :b) '(:a . :doesnt-match)))
(true-or-false? ____ (equalp #\S #\S)) (true-or-false? t (equalp #\S #\S))
(true-or-false? ____ (equalp "Foo" "Foo")) (true-or-false? t (equalp "Foo" "Foo"))
(true-or-false? ____ (equalp "Foo" (copy-seq "Foo"))) (true-or-false? t (equalp "Foo" (copy-seq "Foo")))
(true-or-false? ____ (equalp "FOO" "Foo")) (true-or-false? t (equalp "FOO" "Foo")) ; this one didn't get on first try
(true-or-false? ____ (equalp (make-array '(4 2) :initial-element 0) (true-or-false? t (equalp (make-array '(4 2) :initial-element 0)
(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)))) (make-thing :slot-1 42 :slot-2 :forty-two))))
;;; In additional to the generic equality predicates, Lisp also provides ;;; In additional to the generic equality predicates, Lisp also provides
@ -95,27 +95,27 @@
(define-test = (define-test =
;; The function = behaves just like EQUALP on numbers. ;; The function = behaves just like EQUALP on numbers.
;; #C(... ...) is syntax sugar for creating a complex number. ;; #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? t (= 99.0 99 99.000 #C(99 0) #C(99.0 0.0)))
(true-or-false? ____ (= 0 1 -1)) (true-or-false? nil (= 0 1 -1))
(true-or-false? ____ (= (/ 2 3) (/ 6 9) (/ 86 129)))) (true-or-false? t (= (/ 2 3) (/ 6 9) (/ 86 129))))
(define-test string= (define-test string=
;; The function STRING= behaves just like EQUAL on strings. ;; The function STRING= behaves just like EQUAL on strings.
;; The function STRING-EQUAL behaves just like EQUALP on strings. ;; The function STRING-EQUAL behaves just like EQUALP on strings.
(true-or-false? ____ (string= "Foo" "Foo")) (true-or-false? t (string= "Foo" "Foo"))
(true-or-false? ____ (string= "Foo" "FOO")) (true-or-false? nil (string= "Foo" "FOO"))
(true-or-false? ____ (string-equal "Foo" "FOO")) (true-or-false? t (string-equal "Foo" "FOO"))
;; These functions accept additional keyword arguments that allow one to ;; These functions accept additional keyword arguments that allow one to
;; only compare parts of the strings. ;; 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)) :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))) :start2 2)))
(define-test char= (define-test char=
;; The function CHAR= behaves just like EQL on characters. ;; The function CHAR= behaves just like EQL on characters.
;; The function CHAR-EQUAL behaves just like EQUALP on characters. ;; The function CHAR-EQUAL behaves just like EQUALP on characters.
(true-or-false? ____ (char= #\A (char "ABCDEF" 0))) (true-or-false? t (char= #\A (char "ABCDEF" 0)))
(true-or-false? ____ (char= #\A #\a)) (true-or-false? nil (char= #\A #\a))
(true-or-false? ____ (char-equal #\A (char "ABCDEF" 0))) (true-or-false? t (char-equal #\A (char "ABCDEF" 0)))
(true-or-false? ____ (char-equal #\A #\a))) (true-or-false? t (char-equal #\A #\a)))

View File

@ -16,69 +16,88 @@
(define-test make-hash-table (define-test make-hash-table
(let ((my-hash-table (make-hash-table))) (let ((my-hash-table (make-hash-table)))
(true-or-false? ____ (typep my-hash-table 'hash-table)) (true-or-false? t (typep my-hash-table 'hash-table))
(true-or-false? ____ (hash-table-p my-hash-table)) (true-or-false? t (hash-table-p my-hash-table))
(true-or-false? ____ (hash-table-p (make-array '(3 3 3)))) (true-or-false? nil (hash-table-p (make-array '(3 3 3))))
;; The function HASH-TABLE-COUNT returns the number of entries currently ;; The function HASH-TABLE-COUNT returns the number of entries currently
;; contained in a hash table. ;; 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 (define-test gethash
;; The function GETHASH can be used to access hash table values. ;; The function GETHASH can be used to access hash table values.
(let ((cube-roots (make-hash-table))) (let ((cube-roots (make-hash-table)))
;; We add the key-value pair 1 - "uno" to the hash table. ;; We add the key-value pair 1 - "uno" to the hash table.
(setf (gethash 1 cube-roots) "uno") (setf (gethash 1 cube-roots) "uno")
(assert-equal ____ (gethash 1 cube-roots)) (assert-equal "uno" (gethash 1 cube-roots))
(assert-equal ____ (hash-table-count cube-roots)) (assert-equal 1 (hash-table-count cube-roots))
(setf (gethash 8 cube-roots) 2) (setf (gethash 8 cube-roots) 2)
(setf (gethash -3 cube-roots) -27) (setf (gethash -3 cube-roots) -27)
(assert-equal ____ (gethash -3 cube-roots)) (assert-equal -27 (gethash -3 cube-roots))
(assert-equal ____ (hash-table-count cube-roots)) (assert-equal 3 (hash-table-count cube-roots))
;; GETHASH returns a secondary value that is true if the key was found in ;; GETHASH returns a secondary value that is true if the key was found in
;; the hash-table and false otherwise. ;; the hash-table and false otherwise.
(multiple-value-bind (value foundp) (gethash 8 cube-roots) (multiple-value-bind (value foundp) (gethash 8 cube-roots)
(assert-equal ____ value) (assert-equal 2 value)
(assert-equal ____ foundp)) (assert-equal t foundp))
(multiple-value-bind (value foundp) (gethash 125 cube-roots) (multiple-value-bind (value foundp) (gethash 125 cube-roots)
(assert-equal ____ value) (assert-equal nil value)
(assert-equal ____ foundp)))) (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 (define-test hash-table-test
;; A hash table can be constructed with different test predicates. ;; A hash table can be constructed with different test predicates.
;; The programmer may choose between EQ, EQL, EQUAL, and EQUALP to get the ;; The programmer may choose between EQ, EQL, EQUAL, and EQUALP to get the
;; best performance and expected results from the hash table. ;; best performance and expected results from the hash table.
;; The default test predicate is EQL. ;; The default test predicate is EQL.
(let ((eq-table (make-hash-table :test #'eq)) (let ((eq-table (make-hash-table :test #'eq))
(eql-table (make-hash-table)) (eql-table (make-hash-table))
(equal-table (make-hash-table :test #'equal)) (equal-table (make-hash-table :test #'equal))
(equalp-table (make-hash-table :test #'equalp))) (equalp-table (make-hash-table :test #'equalp)))
;; We will define four variables whose values are strings. ;; We will define four variables whose values are strings.
(let* ((string "one") (let* ((string "one")
(same-string string) (same-string string)
(string-copy (copy-seq string)) (string-copy (copy-seq string))
(string-upcased "ONE")) (string-upcased "ONE"))
;; We will insert the value of each variable into each hash table. ;; We will insert the value of each variable into each hash table.
(dolist (thing (list string same-string string-copy string-upcased)) (dolist (thing (list string same-string string-copy string-upcased))
(dolist (hash-table (list eq-table eql-table equal-table equalp-table)) (dolist (hash-table (list eq-table eql-table equal-table equalp-table))
(setf (gethash thing hash-table) t)))) (setf (gethash thing hash-table) t))))
;; How many entries does each hash table contain? ;; How many entries does each hash table contain?
(assert-equal ____ (hash-table-count eq-table)) (assert-equal 3 (hash-table-count eq-table))
(assert-equal ____ (hash-table-count eql-table)) (assert-equal 3 (hash-table-count eql-table)) ; didn't get that on first try
(assert-equal ____ (hash-table-count equal-table)) ;; i guess eql still not compares strings
(assert-equal ____ (hash-table-count equalp-table)))) (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 (define-test hash-table-equality
;; EQUALP considers two hash tables to be equal if they have the same test and ;; 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. ;; if its key-value pairs are the same under that test.
(let ((hash-table-1 (make-hash-table :test #'equal)) (let ((hash-table-1 (make-hash-table :test #'equal))
(hash-table-2 (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-1) "yat")
(setf (gethash "one" hash-table-2) "yat") (setf (gethash "one" hash-table-2) "yat")
(setf (gethash "two" hash-table-1) "yi") (setf (gethash "two" hash-table-1) "yi")
(setf (gethash "two" hash-table-2) "yi") (setf (gethash "two" hash-table-2) "yi")
(true-or-false? ____ (eq hash-table-1 hash-table-2)) (true-or-false? nil (eq hash-table-1 hash-table-2))
(true-or-false? ____ (equal hash-table-1 hash-table-2)) (true-or-false? nil (equal hash-table-1 hash-table-2))
(true-or-false? ____ (equalp 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 (define-test i-will-make-it-equalp
;; Disabled on ECL due to a conformance bug. ;; Disabled on ECL due to a conformance bug.

View File

@ -22,20 +22,28 @@
(y (multiple-value-list (floor 3/2)))) (y (multiple-value-list (floor 3/2))))
(assert-equal x 1) (assert-equal x 1)
(assert-equal y '(1 1/2))) (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) (defun next-fib (a b)
;; The function VALUES allows returning multiple values. ;; The function VALUES allows returning multiple values.
(values b (+ a b))) (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 (define-test binding-and-setting-multiple-values
;; The macro MULTIPLE-VALUE-BIND is like LET, except it binds the variables ;; 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 ;; listed in its first argument to the values returned by the form that is its
;; second argument. ;; second argument.
(multiple-value-bind (x y) (next-fib 3 5) (multiple-value-bind (x y) (next-fib 3 5)
(let ((result (* x y))) (let ((result (* x y)))
(assert-equal ____ result))) (assert-equal 40 result)))
;; SETF can also set multiple values if a VALUES form is provided as a place. ;; SETF can also set multiple values if a VALUES form is provided as a place.
(let (x y) (let (x y)
(setf (values x y) (next-fib 5 8)) (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?