Question:I’m working with hash tables in Typed Racket, and trying to use the (untyped)
require/typedto import it into my module and call it will pass the type checker and compile.
However, actually running it will cause a contract failure:
#lang typed/racket/base (require/typed racket/hash [hash-union (All (k v) (->* ((Immutable-HashTable k v)) (#:combine (-> v v v) #:combine/key (-> k v v v)) #:rest (HashTable k v) (Immutable-HashTable k v)))]) (: pick-first (All (a) (-> a a a))) (define (pick-first v1 v2) v1) (: make-ci-table (-> String (Immutable-HashTable Char Integer))) (define (make-ci-table pat) (let ([patlen (string-length pat)]) ((inst hash-union Char Integer) (for/hasheqv : (Immutable-HashTable Char Integer) ([i (in-range patlen)]) (values (char-upcase (string-ref pat i)) (- patlen 1 i))) (for/hasheqv : (Immutable-HashTable Char Integer) ([i (in-range patlen)]) (values (char-downcase (string-ref pat i)) (- patlen 1 i))) #:combine pick-first)))
The equivalent in normal Racket runs fine. It appears to be failing in testing if a table is immutable if I’m reading that back trace correctly (Though I have no idea why a chaperone contract is involved, or why it’s getting some other value). Changing the rest type to
raco test: (submod "main.rkt" test) hash/c: contract violation expected: chaperone-contract? given: k33 context...: /usr/share/racket/collects/racket/contract/private/hash.rkt:61:0: hash/c /usr/share/racket/pkgs/typed-racket-lib/typed-racket/utils/hash-contract.rkt:28:0: hash/c/check-key /usr/share/racket/pkgs/typed-racket-lib/typed-racket/utils/hash-contract.rkt:22:0: immutable-hash/c /usr/share/racket/collects/racket/contract/private/parametric.rkt:26:36 /usr/share/racket/collects/racket/contract/private/parametric.rkt:82:7: wrap /usr/share/racket/collects/racket/contract/private/parametric.rkt:100:10 ...
Immutable-HashTabledoesn’t change anything, and the tables returned by TR’s
for/hasheqvare immutable ones.
Any ideas on what’s causing this and how to fix it? (Other than building the final table up with
for/foldor some other alternative approach, which is my plan if I can’t resolve this issue with
Answer:The problem is that polymorphism in the keys of hash tables doesn’t work well with the contracts that Typed Racket puts on it when you import it from untyped Racket. The error message:
hash/c: contract violation expected: chaperone-contract? given: k33
k33which comes from your
(All (k v) .... (Immutable-HashTable k v) ....).
The first step to fixing this error is to use a concrete type like
Anyinstead of a polymorphic
k, as in
(All (v) .... (Immutable-HashTable Any v) ....).
The next error after that might be something like:
This is because
hash-union: contract violation expected: "hash-equal? (because the key contract is not a flat contract)" given: '#hasheqv()
hasheqvdon’t work well with the contracts that Typed Racket puts on it. You can fix that by using
hashalwinstead, as in
(for/hash : (Immutable-HashTable Any Integer) ....).
If you run into other contract problems that you can’t fix in similar ways, it’s also possible to bypass the contracts that Typed Racket puts on it, by importing it unsafely, but that should be a last-resort.
If you have better answer, please add a comment about this, thank you!
If you like this answer, you can give me a coffee by <a href=”https://violencegloss.com/mkw7pgdwwr?key=2a96ade6f3760c7e63343a320febb78e”>click here</a>