Почему нельзя кодировать в #: резервные ссылки ссылаются на универсальные методы? - PullRequest
0 голосов
/ 12 сентября 2018

Этот код:

(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 очень хорошо иллюстрирует, почему запасные варианты - как я их понимаю, во всяком случае - так важны.

1 Ответ

0 голосов
/ 11 июля 2019

Вторая версия вашего кода верна.

Первая версия вашего кода будет работать, если у вас есть запасное определение add-new-thing+id, но, поскольку вы ссылаетесь на любое возможное определение этого метода за пределами резервной области, вам нужно его импортировать.


Фактически, кажется немного повторяющимся, когда приходится снова определять родовой тип внутри запасного предложения. Это потому, что #:fallbacks работает так же, как и #:methods, и, следовательно, имеет то же поведение переопределения обобщенных типов со своими собственными определениями.

Чтобы сделать явным то, что вы переопределяете метод, вам нужно "импортировать" его внутри вашего предложения, используя define/generic (который на самом деле ничего не определяет, это просто импорт общего в контекст).

Как указано в документации для define/generic:

При использовании внутри определений методов, связанных с ключевым словом #: method, привязывает local-id к универсальному для метода-id. Эта форма полезна для специализаций метода для использования универсальных методов (в отличие от локальной специализации) для других значений.

Затем в define-generics:

Синтаксис fallback-impls такой же, как и методы, предоставленные для ключевого слова #: method для struct.

Это означает, что #:fallbacks ведет себя так же, как и использование #:methods в структуре.

Почему?

Логика, лежащая в основе этого поведения, заключается в том, что блоки определения метода, такие как #:methods и #:fallbacks, имеют доступ к своим собственным определениям всех обобщений, так что легко ссылаться на ваш собственный контекст. Чтобы явно использовать универсальный из-за пределов этого контекста, вам нужно использовать define/generic.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...