Search code examples
racketcontract

Dependent contracts for structs in Racket


Suppose I define a struct for a set with its "center".

(struct centered-set (center elems))

I want to guarantee the following conditions.

  • elems is a set.
  • center is an member of elems.

I can express the conditions with #:guard. Is there a way to express the same conditions as a contract?

For functions, ->i works as a combinator for that kind of dependent contracts. How to express dependent contracts for structs?


Solution

  • IIUC, contract-out doesn't support anything like that. However, you can simulate the functionality by providing the constructor and accessors manually with the contract attached:

    #lang racket
    
    (module foo racket
      (provide (contract-out [bt (-> any/c any/c any/c (bst/c 1 10))]
                             [bt-val (-> (bst/c 1 10) any/c)]
                             [bt-left (-> (bst/c 1 10) any/c)]
                             [bt-right (-> (bst/c 1 10) any/c)]))
    
      (define (bst/c lo hi)
        (or/c #f
              (struct/dc bt
                         [val (between/c lo hi)]
                         [left (val) #:lazy (bst/c lo val)]
                         [right (val) #:lazy (bst/c val hi)])))
    
      (struct bt (val left right)))
    
    (require 'foo)
    
    (bt 11 #f #f)
    

    It should be possible to write a provide transformer to automate this process.