Примеры того, что можно сделать.
(defmethod some-fn ((num real))
(print "an integer"))
(defmethod some-fn ((num real))
(print "a real"))
(defmethod some-fn ((num (eql 0)))
(print "zero"))
(some-fn 19323923198319)
"an integer"
(some-fn 19323923198319.3)
"a real"
(some-fn 0)
"zero"
Это также работает с общим 'строковым типом.
(defmethod some-fn ((num string))
(print "a string"))
(some-fn "asrt")
"a string"
Не с определенной строкой, однако
(defmethod some-fn ((num (eql "A")))
(print "a specifict string")))
(some-fn "A")
=> "A string"
Я предполагаю, что это не работает, потому что eql не работает над строками в пути, который был бы необходим для него работать.
(eql "a" "a") => nil
Существует ли способ сделать это?
Краткий ответ: Да, есть.
Длинный ответ:
Вы написали:
(defmethod some-fn ((num (eql "A")) (print "a specifict string")))
=> doesn't compile
Это потому, что вы неправильно написали синтаксис . Это должно быть:
(defmethod some-fn ((num (eql "A"))) (print "a specific string"))
=> does compile
Что обычно форматируется как:
(defmethod some-fn ((num (eql "A")))
(print "a specifict string"))
Если вы отформатируете его таким образом и воспользуетесь встроенным инструментом отступа вашего любимого редактора, вы увидите, что отступ выглядит неправильно для вашего кода:
(defmethod some-fn ((num (eql "A"))
(print "a specifict string")))
Также может помочь понять сообщение об ошибке, отображаемое компилятором.
Вернуться к теме:
Вы можете использовать строки как любой другой объект Lisp для отправки EQL в CLOS.
Просто существует много возможных строк, которые выглядят как «A», и EQL сравнивает их идентичность (за исключением чисел и символов). EQL не сравнивает строки по их символам.
Обычно (EQL "A" "A") возвращает NIL. (Примечание: на самом деле в коде, скомпилированном компилятором, это выражение теоретически может быть T. Поскольку компилятору разрешено повторно использовать объекты данных для экономии места в скомпилированном коде. Здесь у нас есть буквальные строки, объекты данных.)
Если вы введите в командной строке
(some-fn "A")
, это не вызовет отправку EQL.
Но это работает так, как ожидалось:
(defparameter *a-string* "A")
(defmethod some-fn ((num (eql *a-string*)))
(print "a specific string")))
, а затем
(some-fn *a-string*)
Вы должны убедиться, что переменная имеет значение.Переменная вычисляется, когда вычисляется макрорасширение формы DEFMETHOD. Тогда значение - это объект, который используется для отправки EQL.
Как упомянул Дирк в своем ответе, можно использовать символы. Назначение символов состоит в том, что (EQL '| A |' | A |) обычно является T. Символы преобразуются в эквалайзер в процессе чтения.
Резюме:
Диспетчер EQL по строкам работает в CLOS. Для практического использования вам нужно вызывать функцию с такой же, с точки зрения EQL, строкой.
К сожалению, насколько я знаю, нет. Специализатор eql
использует только eql
для сравнения (которое по сути является сравнением указателей для строк). Чтобы сравнить содержимое строк, вам понадобится специализатор equal
(или equalp
), которого не существует.
Если у вас есть только очень маленький набор строк, на которых вам нужно специализироваться, вы можете рассмотреть возможность использования ключевых слов:
(defmethod operation ((arg (eql ':tag-1))) ...)
(defmethod operation ((arg (eql ':tag-2))) ...)
которые вы будете вызывать с помощью
(operation (intern ... :keyword))