CLOS имеет eql отправку специализации на строках?

Примеры того, что можно сделать.

(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

Существует ли способ сделать это?

7
задан mhb 30 March 2010 в 22:23
поделиться

2 ответа

Краткий ответ: Да, есть.

Длинный ответ:

Вы написали:

(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, строкой.

7
ответ дан 6 December 2019 в 23:04
поделиться

К сожалению, насколько я знаю, нет. Специализатор eql использует только eql для сравнения (которое по сути является сравнением указателей для строк). Чтобы сравнить содержимое строк, вам понадобится специализатор equal (или equalp), которого не существует.

Если у вас есть только очень маленький набор строк, на которых вам нужно специализироваться, вы можете рассмотреть возможность использования ключевых слов:

(defmethod operation ((arg (eql ':tag-1))) ...)
(defmethod operation ((arg (eql ':tag-2))) ...)

которые вы будете вызывать с помощью

(operation (intern ... :keyword))
4
ответ дан 6 December 2019 в 23:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: