Необязательные аргументы в defgeneric? - PullRequest
8 голосов
/ 20 февраля 2012

Я пишу несколько методов для генерации HTML для различных элементов. Каждый метод имеет одинаковый вывод, но не обязательно требует одинакового ввода.

Метод вывода game-board также должен принимать player (поскольку каждый игрок видит только свои фигуры)

(defmethod echo ((board game-board) (p player)) ... )

Чтобы получить доступ к пространству на доске, не нужно менять каждого игрока (эта диспетчеризация на самом деле выполняется методом game-board, который позже вызывает echo в пространстве). В идеале я бы смог сделать

(defmethod echo ((space board-space)) ... )
(defmethod echo ((space empty-space)) ... )

Также возможно, что позже я столкнусь с объектом, который должен знать больше, чем просто игрок, чтобы правильно отобразить себя. Поскольку уже существуют методы, специализирующиеся на одном и том же универсальном, это может привести к ошибке

The generic function #<STANDARD-GENERIC-FUNCTION ECHO (4)> takes 2 required arguments;

Кажется, не совсем идеально возвращаться и называть эти методы echo-space, echo-board и так далее.

Есть ли канонический способ варьирования других аргументов на основе специализированного объекта? Должен ли я сделать что-то вроде

(defgeneric echo (thing &key player ...) ...)

или

(defgeneric echo (thing &rest other-args) ...)

? В более общем плане, кто-нибудь может указать мне на достойное руководство по defgeneric конкретно? (Я прочитал соответствующие главы PCL и некоторые CLOS учебные пособия , но они не охватывают ситуацию, о которой я здесь спрашиваю).

Ответы [ 3 ]

5 голосов
/ 20 февраля 2012

Вообще говоря, если интерфейсы двух функций слишком разные, это означает, что они на самом деле не являются специализациями одной и той же операции и не должны иметь одинакового имени.Если вы хотите специализироваться только на необязательных / ключевых аргументах, то для этого нужно использовать обычную функцию, которая вызывает обобщенную функцию и предоставляет ей значения по умолчанию для пропущенных аргументов, на которые нужно специализироваться.

Keene'sЯ считаю, что книга является наиболее полным руководством по CLOS.К сожалению, он доступен только в виде книги.

3 голосов
/ 16 апреля 2012

Проще, когда методы принимают одинаковые параметры, но отличаются только типом данных. Но в тех случаях, когда универсальная функция и методы используют одно и то же имя (конечно), но имеют лямбда-списки, которые значительно различаются, я лично склонен использовать & ключевые параметры, чтобы сделать свои намерения явными, вместо использования & необязательных параметров. Я думаю, что это помогает с удобочитаемостью позже.

Попробуйте что-то вроде этого (притворяясь, что у нас уже есть классы class-a и class-b):

(defgeneric foo (object &key &allow-other-keys)
  (:documentation "The generic function. Here is where the docstring is defined."))

(defmethod foo ((object class-a) &key &allow-other-keys)
  (print "Code goes here. We dispatched based on type Class A."))

(defmethod foo ((object class-b) &key (x 1) (y 2) &allow-other-keys)
  (print "Code goes here. We dispatched based on type Class B. We have args X and Y."))

Поскольку задействована «комбинация методов», для того чтобы логика диспетчеризации «перетекла» через возможные варианты выбора используемых методов, нам нужно думать об определениях методов как о цепочке, где несовместимые лямбда-списки (то есть списки параметров) ) разорвет эту цепь. Вот почему в определениях методов есть & key и & allow-other-keys, которые в них не нуждаются. Помещение их в DEFGENERIC и определения методов позволяет нам иметь определение метода, куда мы отправляем, на основе класса-b.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я сам новичок в Common Lisp, так что возьми это с крошкой соли!

0 голосов
/ 21 февраля 2012

Как насчет реструктуризации объектов / классов, чтобы каждый объект, который вы хотите отобразить, имел все необходимые свойства в своих собственных (и унаследованных) слотах?

Таким образом, вам не нужно передавать их в качестве аргументов при вызове echo для объекта, поскольку все, что вам нужно, уже хранится в объекте.

...