Нельзя ли использовать переменные в методах обобщенных функций? (CLOS/LISP)

Я изучаю общие функции в CLOS.

Из-за типов примеров, которые я нахожу в учебниках и онлайн, я очень запутался. В примерах всегда используется тот факт, что существует многократная отправка. В зависимости от типа аргумента выполняется другой расчет. Однако почему сами аргументы никогда не используются в примерах?

Пример кода из Википедии

; declare the common argument structure prototype
(defgeneric f (x y)) 

; define an implementation for (f integer t), where t matches all types
(defmethod f ((x integer) y) 1) 

(f 1 2.0) => 1

; define an implementation for (f integer real)
(defmethod f ((x integer) (y real)) 2) 

(f 1 2.0) => 2 ; dispatch changed at runtime

В приведенных выше примерах вы можете увидеть, что сами методы никогда не используют x или же y переменные. Является ли совпадением то, что во всех этих примерах никогда не используются переменные? Могут ли они быть использованы?

Кроме того, это написано в Википедии:

Методы определяются отдельно от классов и не имеют специального доступа (например, "this", "self" или "protected") к слотам классов.

Итак, методы не имеют "this", потому что они не принадлежат классу. Но почему тогда методы универсальных функций могут иметь получателя? Разве получатель не похож на "это" в классе?

2 ответа

Решение

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

Но почему тогда методы универсальных функций могут иметь получателя? Разве получатель не похож на "это" в классе?

Универсальные функции CLOS не имеют единственного получателя, поэтому нет смысла использовать слово получатель. Реализация, о которой вы упомянули, вероятно, не реализует полный CLOS, но вариант без многократной отправки.

Пример CLOS:

CL-USER 8 > (defmethod plus ((s1 string) (s2 string))
              (concatenate 'string s1 s2))
#<STANDARD-METHOD PLUS NIL (STRING STRING) 4020001E6B>

CL-USER 9 > (plus "foo" "bar")
"foobar"

Вы видите, что обе переменные s1 а также s2 используются. Просто не имеет смысла называть одного из них receiver,

Но вы можете называть переменные так, как вам нравится, и когда ваше приложение использует диспетчеризацию только по первому аргументу, вы можете вызвать эту переменную receiver, но имя не имеет смысла для CLOS. Это просто другое имя.

Обычно для кода CLOS предпочтительно давать аргументам полезные имена.

Это вводит в заблуждение, потому что мы не делаем передачу сообщений в CLOS:

(defmethod plus ((receiver string) (argument string))
   (concatenate 'string receiver argument))

Это более полезно:

(defmethod plus ((string-1 string) (string-2 string))
   (concatenate 'string string-1 string-2))

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

(defmethod f ((x integer) (y symbol))
    (* x x))

(f 3 'foo) => 9

Использование приемника - это просто соглашение. Если вы хотите использовать CLOS аналогично другим языкам ООП, вы можете просто указать тип первого аргумента. И вы могли бы назвать это this или же self чтобы прояснить намерение.

Другие вопросы по тегам