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.