Использование опции :method в defgeneric

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

Представляет ли параметр :method значение по умолчанию или, по крайней мере, документирует то, что, как вы ожидаете, будет наиболее распространенным вариантом использования, или у него есть дополнительная семантика? С точки зрения стиля, если вы предполагаете определить только один метод, имеет ли смысл определять его в форме defgeneric (если вы действительно можете это сделать) или отдельно в форме defmethod? Или вообще не имеет смысла делать дженерик-функцию в этом случае, а вместо нее использовать обычную defun?


person amp108    schedule 15.04.2015    source источник


Ответы (2)


Гиперспецификация со своей обычной ясностью перечисляет :method как вариант для defgeneric, но не говорит, что это значит.

Фактически, запись HyperSpec для defgeneric, с присущей ему ясностью, говорит именно то, что имеет в виду. В нем говорится, что синтаксис для defgeneric:

defgeneric имя-функции gf-лямбда-список [[опция | {метод-описание}*]]

а затем говорит, что синтаксис для описания метода:

описание-метода::= (:метод-спецификатор-метода* специализированный-лямбда-список [[декларация* | документация]] форма*)

Затем он описывает комбинацию методов:

Каждое описание метода определяет метод универсальной функции. Список лямбда-выражений каждого метода должен совпадать со списком лямбда-выражений, заданным параметром gf-lambda-list. Если описания методов не указаны и универсальная функция с таким именем еще не существует, создается универсальная функция без методов.

Таким образом, формы :method предназначены для определения методов универсальной функции, как и формы defmethod.

(Допускаю, что на самом деле ничего не говорится о том, почему вы предпочитаете defgeneric plus :method вместо defmethod. Помните, что Common в Common Lisp означает, что язык является попытка унифицировать множество существующих реализаций Лиспа. Возможно, некоторые из них поддерживали :method, а другие поддерживали defmethod, и это был самый простой способ обеспечить унифицированный интерфейс.)

То есть, следующее будет иметь тот же эффект:

(defgeneric to-list (object))

(defmethod to-list ((object t))
  (list object))

(defmethod to-list ((object list))
  object)

(defgeneric to-list (object)
  (:method ((object t)) 
    (list object))
  (:method ((object list))
    object))

Sometimes it can be convenient to define some of the methods along with the defgeneric form. It's more a matter of style, and this gets into the other parts of your question.

Представляет ли параметр :method значение по умолчанию или, по крайней мере, документирует то, что, как вы ожидаете, будет наиболее распространенным вариантом использования, или у него есть дополнительная семантика?

Это может быть что-то вроде значения по умолчанию, если вы определяете метод без спецификаторов типа или со спецификаторами типа, которые применяются к каждому объекту (например, t).

С точки зрения стиля, если вы предполагаете определить только один метод, имеет ли смысл определять его в форме defgeneric (если вы действительно можете это сделать) или отдельно в методе def? Или вообще не имеет смысла делать дженерик-функцию в этом случае, а вместо этого использовать обычный дефун?

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

Также стоит отметить, что существуют другие формы, которые могут определять методы для универсальной функции (и другие формы, которые также могут создавать общие функции). В HyperSpec использование стрелок вверх для перехода к более высоким разделам обычно приводит к более подробной информации. В этом случае полезно ознакомиться с 7.6.1 Введение в базовые функции. :

Некоторые операторы определяют методы универсальной функции. Эти операторы будут называться операторами определения метода; связанные с ними формы называются формами определения метода. Стандартизированные операторы определения метода перечислены на следующем рисунке.

defgeneric        defmethod  defclass  
define-condition  defstruct
person Joshua Taylor    schedule 15.04.2015
comment
CLOS в основном был основан на Flavors/New Flavors и LOOPS/CommonLOOPS. Многие методы могут быть длинными и обычно не любят помещать несколько из них в одну длинную форму. Кроме того, один метод делает переопределение проще/быстрее... - person Rainer Joswig; 15.04.2015
comment
Спасибо. Возможно, гиперспектакль предназначен для людей с лучшим зрением, чем у меня. (Я не могу поверить, что позволил ему быть там, когда я имел в виду его.) - person amp108; 15.04.2015
comment
@ amp108 На самом деле есть и другие формы, которые вводят методы для универсальных функций (а в некоторых случаях также вводят универсальные функции). Это обсуждается в некоторых прозаических частях гиперспецификации; Я обновил свой ответ абзацем в конце. - person Joshua Taylor; 15.04.2015

Это зависит от личных предпочтений и того, как система будет организована в исходном коде. Либо

  • простая универсальная функция: набор DEFMETHODS

  • сложная универсальная функция: DEFGENERIC и куча DEFMETHODS

  • общая функция: DEFGENERIC и куча методов внутри

Большинство объектно-ориентированных систем Lisp до CLOS использовали форму определения единого метода. В противном случае код мог бы стать слишком длинным в одной форме, универсальных функций в большинстве случаев не существовало...

В системах с одинарной отправкой, ориентированных на классы, было бы целесообразно организовать методы в определении класса. С введением универсальных функций и множественной диспетчеризации имело смысл организовать их в соответствии с определением универсальной функции.

person Rainer Joswig    schedule 15.04.2015