Search code examples
racketdesign-by-contract

(or/c #f <contract>) vs <contract>


According to the following example from the struct/dc entry in the Racket reference manual, the bst/c function below returns a contract such as every node in bt has its value bound between lo and hi.

(struct bt (val left right))

(define (bst/c lo hi)
  (or/c #f
        (struct/dc bt
                   [val (between/c lo hi)]
                   [left (val) #:lazy (bst lo val)]
                   [right (val) #:lazy (bst val hi)])))

That definition looks perfect to me, except for one thing: what is the purpose of the (or/c #f [...]) construct here ? Since #f is a constant that always evaluates to false, why not just remove the or/c logic altogether, and simply define bst/c as:

(define (bst/c lo hi)
  (struct/dc bt
             [val (between/c lo hi)]
             [left (val) #:lazy (bst lo val)]
             [right (val) #:lazy (bst val hi)]))

Solution

  • A binary search tree with a single value is constructed as:

     (bst 42 #f #f)
    

    Here #f is used to indicated that the left and right subtrees are empty.

    Since we want the left and right subtrees also to be binary search trees, we need to include the value #f as a legal bst. The contract (or/c #f ...) says just that.