specifying a slot value as a key when removing duplicates

204 views Asked by At

The following code does what I want:

 1 (defclass some-class ()
 2   ((some-slot
 3       :initarg :somearg
 4       :initform (error ":somearg not specified"))))
 5 (defparameter *alpha* (make-instance 'some-class :somearg 3))
 6 (defparameter *beta*  (make-instance 'some-class :somearg 5))
 7 (defparameter *gamma* (make-instance 'some-class :somearg 3))
 8 (princ (slot-value *beta* 'some-slot)) (terpri)
 9 (defparameter *delta* (list *alpha* *beta* *gamma*))
10 (princ *delta*) (terpri)
11 (princ (remove-duplicates *delta*
12          :test #'equal
13          :key (lambda (x) (slot-value x 'some-slot))))
14 (terpri)
5
(#<SOME-CLASS #x21C1D71E> #<SOME-CLASS #x21C1DAFE> #<SOME-CLASS #x21C1DC3E>)
(#<SOME-CLASS #x21C1DAFE> #<SOME-CLASS #x21C1DC3E>)

But is there a way to do this without having to write the function on line 13? Is there a shorthand way to specify as the key a slot value in the class instance?

The following blows up with a syntax error, of course, but it gives the general idea of what I'm seeking.

 1 (princ (remove-duplicates *delta*
 2          :test #'equal
 3          :key '(slot-value 'some-slot)))
 4 (terpri)
*** - FUNCALL: (SLOT-VALUE 'SOME-SLOT) is not a function name; try using a
      symbol instead
2

There are 2 answers

2
Inaimathi On BEST ANSWER

You could try a :reader or :accessor.

Doing

(defclass some-class ()
  ((some-slot
    :initarg :somearg :reader some-slot
    :initform (error ":somearg not specified"))))

should let you re-write lines 11 through 13 as

(princ (remove-duplicates *delta* :test #'equal :key #'some-slot))

That is, (some-slot x) is equivalent to (slot-value x 'some-slot) if the slot in question has a reader/accessor.


After-Sleep Edit:

You also don't need to bother setting :initform to error; a slot will do that by default if you don't specify a default value and someone tries to read it. If you don't want the error, you do something like :initform nil. Check out this excellent CLOS tutorial as well as chapters 16 and 17 of Practical Common Lisp for more information about objects in Common Lisp.

Also, in the future if you have working code that you'd like style advice on, do check out codereview.stackexchange. There's a small, but active population of Lisp reviewers.

0
Rörd On

You could define a reader function for the slot in the defclass and provide that as key function to remove-duplicates. For example, add this line to the slot definition:

:reader some-slot

and then use this in the call of remove-duplicates:

:key #'some-slot