Поддерживают ли такие проверки, как «хэш?» в Racket, утиный ввод?

Я программист Python, новичок в Racket...

Я видел такой код, как:

(define table/c (and/c hash? (not/c immutable?)))

Я понимаю, что это использование контрактов, то есть https://docs.racket-lang.org/reference/data-structure-contracts.html#%28def._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._and%2Fc%29%29

Таким образом, это означает, что любое место в этой библиотеке, принимающее table/c arg, должно быть объектом, представляющим собой изменяемую хеш-таблицу.

Мой вопрос: есть ли у Racket какая-либо поддержка утиного ввода здесь (в частности, для выполнения контракта hash?)?

Скажем, я хотел заменить базовую хэш-таблицу чем-то, поддерживаемым хранилищем k/v... Могу ли я реализовать интерфейс «хэш-таблицы», который позволил бы моему пользовательскому объекту, поддерживаемому хранилищем, пройти проверку контракта hash??

Документы по контрактам и это для hash? проверки мне мало помогло.


person Anentropic    schedule 19.07.2020    source источник
comment
Вероятно, вы могли бы сделать это со словарями, реализовав интерфейс gen:dict. Однако hash? не будет верным, а dict? пройдет.   -  person Alex Knauth    schedule 19.07.2020
comment
Мне особенно нужна проверка hash? для библиотеки, с которой я работаю. В Python я мог бы проделать какой-нибудь трюк с абстрактными базовыми классами, чтобы почти любой тип мог пройти проверку isinstance, как и любой другой тип. В противном случае можно ли отказаться от проверки контрактов, когда я использую библиотеку?   -  person Anentropic    schedule 19.07.2020
comment
Я просмотрел исходный код Racket и нашел этот github.com/racket/racket/blob/ Выглядит многообещающе: может быть, я смогу сделать имперсонатор хэша? Я немного озадачен, почему я могу найти его только как файл .ss в папке cs/, что звучит как что-то специфичное для Racket CS с бэкендом Chez.   -  person Anentropic    schedule 19.07.2020
comment
Однако Impersonator принимает конкретный хэш в качестве входных данных, поэтому я не думаю, что это не то, что вам нужно. Что не так с использованием dict? hash не предназначен для расширения, но dict является.   -  person Sorawee Porncharoenwase    schedule 19.07.2020
comment
Я хочу передать свой пользовательский объект методу чужой библиотеки, который определяет контракт как hash?, поэтому, как я объяснил в вопросе, я пытаюсь найти способ пройти проверку hash?   -  person Anentropic    schedule 19.07.2020
comment
Я думаю, что в моем случае имперсонатор для конкретного хэша подойдет, я действительно хочу хеш-таблицу, которая похожа на кеш со сквозной записью для чего-то, что сохраняется на диске. Так что я мог бы, возможно, создать имперсонатор реального конкретного экземпляра хэша, где ключевые операции вставки/обновления/удаления «перенаправляются» на мои пользовательские методы объекта... Я попробую этот impersonate-hash метод docs.racket-lang.org/reference/   -  person Anentropic    schedule 19.07.2020


Ответы (1)


Я думаю, что вы действительно хотите использовать словари для этого, но если вы застряли с библиотекой, которая хочет hash? для проверки контракта, вы можете использовать подражатели.

Вот функция, которую я написал, которая пытается использовать слабый хеш, имеет кеш для некоторых, возможно, дорогостоящих вычислений, представленных (неправильно названной) функцией filler, которая будет вызываться для отсутствующего ключа.

Я довольно не уверен в семантике такого рода вещей (и я не эксперт ни в чем из этого), но на практике это работает.

(define (make-cache filler)
  (impersonate-hash
   (make-weak-hash '())
   (λ (ht key)
     ;; impersonate hash-ref by calling the filler
     (unless (hash-has-key? ht key)
       ;; I think this is safe as the key won't be dropped
       (hash-set! ht key (filler key)))
     (values key (λ (ht k v) v)))
   ;; Everything else is passed through
   (λ (ht k v)
     (values k v))
   (λ (ht k)
     k)
   (λ (ht k)
     k)))
person Community    schedule 22.07.2020