Необязательные аргументы в DefEreneric?
-
28-10-2019 - |
Вопрос
Я пишу некоторые методы для излучения 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. К сожалению, это кажется доступным только в форме книги.
Другие советы
Это проще, когда методы принимают одинаковые параметры, но различаются только на типе данных. Но в тех случаях, когда общая функция и методы все используют одно и то же имя (конечно), но в них есть списки Lambda, которые значительно различаются, я лично склонен использовать и ключевые параметры, чтобы сделать мои намерения явными, а не использование и необязательные параметры. Я думаю, что это помогает с читаемости позже.
Попробуйте что-то подобное (притворяясь, что у нас уже есть классы класса 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."))
Поскольку «комбинация методов» задействована, чтобы логика диспетчеризации «тела» через его возможный выбор методов для использования, нам необходимо подумать о определениях метода, как цепь, где несовместимые списки лямбда (IE списки параметров) разорвутся эта цепь. Вот почему в определениях методов, которые они конкретно не нуждаются в том, что в определениях методов, которые они конкретно не нужны. Поместить их в DefEreneric и определения метода позволяет нам иметь определение метода, в котором мы отправляем на основе класса-B.
Отказ от ответственности: я сам обычный новичок LISP, так что возьмите это с зерном соли!
Как насчет реструктуризации объектов/классов, чтобы каждый объект, который вы хотите повторить, имел все необходимые свойства в своих (и унаследованных) слотах?
Таким образом, вам не нужно передавать их в качестве аргументов, когда вы называете Echo на объекте, поскольку то, что вам нужно, уже хранится в объекте.