Package its
Description
Simply import its and their for normal usage. Don't (:use)!
This package will be mostly designed for explicit qualification of symbols when it exports more symbols, such as its:expand-specification.
its provides convenient access to multiple values of an object in a concise, explicit and efficient way.
(its cons (cons 'foo 'bar))
==
(its (cons t) (cons 'foo 'bar))
==
(its (cons :car :cdr) (cons 'foo 'bar))
==
(let ((my-cons (cons 'foo 'bar)))
(values (car my-cons) (cdr my-cons)))
=>
foo, bar
(let ((fun (its (cons t))))
(multiple-value-call #'values
(funcall fun '(foo . bar))
(funcall fun '(foo2 . bar2))))
==
(let ((fun (lambda (my-cons)
(its (cons t) my-cons))))
(multiple-value-call #'values
(funcall fun '(foo . bar))
(funcall fun '(foo2 . bar2))))
==
(multiple-value-call #'values
(its cons '(foo . bar))
(its (cons :car :cdr) '(foo2 . bar2)))
==
(their cons '(foo . bar) '(foo2 . bar2))
=>
foo, bar, foo2, bar2
(its (hash-table (gethash 'foo) (gethash 'bar) (gethash 'baz 'no-baz))
(let ((hash (make-hash-table :test 'eq)))
(prog1 hash
(setf (its (hash-table (gethash 'foo) (gethash 'bar)) hash)
(values 'my-foo 'my-bar)))))
==
(let ((hash (make-hash-table :test 'eq)))
(setf (gethash 'foo hash) 'my-foo
(gethash 'bar hash) 'my-bar)
(values (gethash 'foo hash)
(gethash 'bar hash)
(gethash 'baz hash 'no-baz)))
=>
my-foo, my-bar, no-baz
(defclass coords ()
((x :initarg :x)
(y :initarg :y)
(z :initarg :z)))
(its (t (slot-value 'x 'y)
(slot-exists-p 'z)
(slot-boundp 'z))
(make-instance 'coords :x 0 :y 1))
==
(let ((coords (make-instance 'coords :x 0 :y 1)))
(values (slot-value coords 'x)
(slot-value coords 'y)
(slot-exists-p coords 'z)
(slot-boundp coords 'z)))
=>
0, 1, t, nil
(defclass coords ()
((x :initarg :x :accessor x)
(y :initarg :y :accessor y)
(z :initarg :z :accessor z)))
(defsys:define (its coords) (coords)
(:x () `(x ,coords))
(:y () `(y ,coords))
(:z () `(z ,coords))
(t (:x :y :z)))
(let ((my-coords (make-instance 'coords :x 0 :y 1)))
(setf (its (coords :z :x) my-coords)
(values 2 -1))
(its coords my-coords))
==
(let ((my-coords (make-instance 'coords :x 0 :y 1)))
(setf (values (z my-coords) (x my-coords))
(values 2 -1))
(values (x my-coords) (y my-coords) (z my-coords)))
=>
-1, 1, 2
(let ((my-coords (make-instance 'coords :x 0 :y 4 :z 8)))
(multiple-value-call #'format nil "At (~A, ~A, ~A)."
(its coords my-coords)))
=>
"At (0, 4, 8)."
(their cons '(foo) '(bar) '(baz quux))
==
(let ((function (their cons (3)))) ;efficient
(funcall function '(foo) '(bar) '(baz quux)))
==
(let ((function (their cons))) ;inefficient
(funcall function '(foo) '(bar) '(baz quux)))
=>
foo, nil, bar, nil, baz, (quux)
(let ((cons1 (cons 'cons1-car 'cons1-cdr))
(cons2 (cons 'cons2-car 'cons2-cdr)))
(setf (their cons cons1 cons2)
(values 'cons1-new-car 'cons1-new-cdr
'cons2-new-car 'cons2-new-cdr))
(values cons1 cons2))
==
(let ((cons1 (cons 'cons1-car 'cons1-cdr))
(cons2 (cons 'cons2-car 'cons2-cdr)))
(setf (values (car cons1) (cdr cons1)
(car cons2) (cdr cons2))
(values 'cons1-new-car 'cons1-new-cdr
'cons2-new-car 'cons2-new-cdr))
(values cons1 cons2))
=>
(cons1-new-car . cons1-new-cdr),
(cons2-new-car . cons2-new-cdr)
;;;Last "t" in object position is evaluated but ignored.
(its (values :lisp-implementation :machine) t)
==
(its (values (:lisp-implementation t) (:machine t)) t)
==
(its (values (:lisp-implementation :type :version)
(:machine :instance :type :version))
t)
==
(multiple-value-call #'values
(its :lisp-implementation t)
(its :machine t))
==
(multiple-value-call #'values
(its (:lisp-implementation t) t)
(its (:machine t) t))
==
(multiple-value-call #'values
(its (:lisp-implementation :type :version) t)
(its (:machine :instance :type :version) t))
==
(multiple-value-call #'values
(values (lisp-implementation-type)
(lisp-implementation-version))
(values (machine-instance)
(machine-type)
(machine-version)))
=> ;Results may vary. ;P
"SBCL", "1.4.13", "dynamorph", "X86-64",
"Intel(R) Celeron(R) CPU J1800 @ 2.41GHz"
Simply import its and their for normal usage. Don't (:use)!
This package will be mostly designed for explicit qualification of symbols when it exports more symbols, such as its:expand-specification.
specification &optional object
object is required for (setf its).
If object is provided, then object is evaluated first, then specification is evaluated from left to right.
If object is not provided, then a function equivalent to (lambda (object) (its specification object)) is returned.
For now, see the examples for inspiration.
specification &body objects
There must be at least one object for (setf their).
their with one object is exactly equivalent to its with the same arguments.
If at least one object is provided, then objects are evaluated first from left to right, then specification is evaluated from left to right.
If no objects are provided, then a function accepting any number of object arguments is returned. This function returns the concatenation of the results of applying the specification to each of the objects in turn. To avoid expensive runtime concatenation of multiple values, one can (and normally should) provide the number of expected arguments. The function will then accept exactly that many objects. See the relevant example.
(&optional object-var) &body clauses => kind
Each clause defines an access specifier for the kind named kind-name, which is created if necessary.
Each clause is of the form (name lambda-list form) or (t (&rest access-specifiers)).
For now, look in definitions.lisp for inspiration.