Этот код:
(require racket/generic)
;; A holder that assigns ids to the things it holds. Some callers want to know the
;; the id that was assigned when adding a thing to the holder, and others don't.
(define-generics holder
(add-new-thing+id holder new-thing) ;returns: holder id (two values)
(add-new-thing holder new-thing) ;returns: holder
#:fallbacks
[(define (add-new-thing holder new-thing) ;probably same code for all holder structs
(let-values ([(holder _) (add-new-thing+id holder new-thing)])
holder))])
выдает это сообщение об ошибке:
add-new-thing+id: method not implemented in: (add-new-thing+id holder new-thing)
Я могу это исправить, добавив define/generic
в запасные варианты, например:
#:fallbacks
[(define/generic add add-new-thing+id)
(define (add-new-thing holder new-thing)
(let-values ([(holder _) (add holder new-thing)])
holder))])
но это, кажется, добавляет сложности без добавления ценности, и я не понимаю, почему один работает, а другой нет.
Как я понимаю #:fallbacks
, идея в том, что универсальное определение может создавать методы из самых примитивных методов, поэтому структуры, реализующие универсальный интерфейс, не всегда должны переопределять один и тот же большой набор методов, который обычно просто вызывать основные методы с идентичным кодом, но они могут переопределять эти «производные» методы, если это необходимо. скажем, для оптимизации. Это очень полезная вещь * - но я неправильно понял запасные варианты?
Кажется странным, что резервный код не может ссылаться на универсальные методы. Разве не главная ценность запасных вариантов их называть? Документация для define/generic
говорит, что это синтаксическая ошибка, вызывать ее вне предложения #:methods
в определении структуры, поэтому я, вероятно, неправильно ее использую. В любом случае, кто-то может объяснить, каковы правила для кода в предложении #:fallbacks
? Как ты должен написать?
* В мире Clojure есть нечто похожее, в библиотеках potemkin
def-abstract-type
и deftype+
, но они не так хорошо интегрированы в язык. potemkin/def-map-type
очень хорошо иллюстрирует, почему запасные варианты - как я их понимаю, во всяком случае - так важны.