Нельзя ли использовать переменные в методах обобщенных функций? (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
чтобы прояснить намерение.