2014-11-23 2 views
4

То, что я пытаюсь сделать это:Defmethod на произвольных спецификаторах типов?

(defgeneric fn (x)) 

(defmethod fn ((x (integer 1 *))) 
    "Positive integer") 

(defmethod fn ((x (integer * -1))) 
    "Negative integer") 

Я хочу обобщенную функцию, которая работает с произвольными спецификаторов типа, в том числе на основе списка из них, такие как (and x y), (or x y), (satisfies p) и т.д. Теперь, когда я попытайтесь запустить вышеуказанный код, я получаю ошибку «Invalid Specializer». Немного исследований показывает, что defgeneric предназначен для работы с CLOS, а не с произвольными спецификаторами типов. Есть ли в Common Lisp система с дегенерирующими свойствами, которая бы обеспечила мне поведение, которое я хочу для произвольных спецификаторов типов, а не только для классов?

+0

Нуль положительный и отрицательный? –

+0

@RainerJoswig Исправлено, но на самом деле это не меняет цели вопроса. –

+0

true, но это создает проблему такой функции. Если оба метода совпадают: какой из них использовать? Методы не могут быть упорядочены ... Для нуля оба метода были сопоставлены. Какой из них следовало использовать? –

ответ

7

Общие Lisp определяет две иерархии, которые связаны друг с другом, но не идентичны: иерархия типов и иерархия классов. Каждый класс является типом, но обратное неверно - существуют типы, которые не являются классами. Например, integer и string являются классами, а значит, и типами. С другой стороны, (integer 1 *) и (satisfies evenp) являются типами, но не классами.

> (type-of "toto") 
(SIMPLE-BASE-STRING 4) 
> (class-of "toto") 
#<BUILT-IN-CLASS STRING> 

Параметр specialisers - вещи, которые вы положили после того, как параметры в defmethod - могут быть только имена классов (или формы (eql value)). Поскольку (integer 1 *) не является именем класса, ваш код не разрешен Common Lisp.Существует отличная причина для этого: компилятор всегда может определить иерархию классов, в то время как тип языка является слишком мощным для этого:

(defun satisfies-the-collatz-conjecture (n) 
    (cond 
    ((<= n 1) t) 
    ((evenp n) (satisfies-the-collatz-conjecture (/ n 2))) 
    (t (satisfies-the-collatz-conjecture (+ 1 (* n 3)))))) 

(subtypep 'integer '(satisfies satisfies-the-collatz-conjecture)) 
NIL ; 
NIL 

Если вам действительно нужен код, чтобы быть модульным, вам нужно будет сначала классифицировать ваши ценности в то, что может быть сделано в specialiser, а затем направить на что:

(defmethod fn-generic (x (sign (eql 'positive))) 
    "Positive integer") 

(defmethod fn-generic (x (sign (eql 'negative))) 
    "Negative integer") 

(defun classify (x) 
    (cond 
    ((< x 0) 'negative) 
    ((= x 0) 'null) 
    ((> x 0) 'positive))) 

(defun fn (x) 
    (fn-generic x (classify x))) 
6

Нет ничего как CLOS, который обеспечит такую ​​функцию.

Это действительно не подходит для CLOS. Подумайте о следующем, мы имеем следующий вызов функции общего:

(generic-function-foo 2) 

Теперь у нас есть методы, определенные для следующих типов:

(integer 0 9) 
(integer 1 9) 
(integer 0 99) 
(integer 1 99) 
(integer -1000 1000) 
(or (satisfies evenp) (integer 0 30)) 
(satisfies evenp) 
(satisfies divisible-by-two) 
(satisfies all-numbers-which-are-in-my-list-of-numbers) 

Какой из методов, которые весь матч за 2 должен работать ? Если я позвоню CALL-NEXT-METHOD, какой из них будет следующим?

Теперь мы можем сказать, упорядочить их по внешнему виду в источнике. Но в Common Lisp вы можете добавлять, удалять или переопределять методы во время выполнения. Поведение было бы более или менее случайным.

Нам нужна другая схема разрешения конфликтов. Например:

  • вручную объявляя приоритет
  • какое-то приоритетное значение
  • ошибки во время выполнения с возможностью для пользователя, чтобы выбрать один
  • язык типа, который обеспечивает приказ
  • даяние все вместе

Были попытки предоставить более выразительную отправку CLOS. Однако я не знаю о добавлении типов в CLOS. См. предикат отправки и отфильтрованная отправка.

Помимо этого я бы искал систему на основе правил, но обычно это сильно отличается от CLOS, Common Object Lisp Object System, если она каким-то образом не интегрирована.

1

то, что вы на самом деле, кажется, ищет это шаблону, как в ML или Erlang. Это совсем другая концепция от отправки, хотя у них одинаковые цели.

Один популярный шаблон для библиотеки Common Lisp - optima (доступно в Quicklisp).

Смежные вопросы