указание значения слота в качестве ключа при удалении дубликатов - PullRequest
4 голосов
/ 29 января 2012

Следующий код делает то, что я хочу:

 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>)

Но есть ли способ сделать это без необходимости писать функцию в строке 13? Есть ли сокращенный способ указать в качестве ключа значение слота в экземпляре класса?

Конечно, следующая ошибка с синтаксической ошибкой, но она дает общее представление о том, что я ищу.

 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 ]

3 голосов
/ 29 января 2012

Вы можете попробовать :reader или :accessor.

Выполнение

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

должно позволить вам переписать строки с 11 по 13 как

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

То есть (some-slot x) эквивалентно (slot-value x 'some-slot), если в соответствующем слоте есть считыватель / аксессор.


Редактирование после сна:

Вам также не нужнопотрудиться установить :initform на ошибку;слот будет делать это по умолчанию, если вы не укажете значение по умолчанию и кто-то попытается его прочитать.Если вы не хотите получить ошибку, вы делаете что-то вроде :initform nil.Посмотрите этот превосходный учебник CLOS , а также главы 16 и 17 Практического общего лиспа для получения дополнительной информации об объектах в Common Lisp.

Кроме того, в будущем, еслиу вас есть рабочий код, который вы хотели бы получить совет по стилю, проверьте codereview.stackexchange .Есть небольшое, но активное население рецензентов Lisp.

2 голосов
/ 29 января 2012

Вы можете определить функцию считывателя для слота в defclass и указать ее как ключевую функцию для remove-duplicates. Например, добавьте эту строку в определение слота:

:reader some-slot

, а затем используйте это в вызове remove-duplicates:

:key #'some-slot
...