[plt-scheme] Contract for SRFI 19

From: Robby Findler (robby at cs.uchicago.edu)
Date: Mon Mar 15 20:06:02 EST 2004

At Mon, 15 Mar 2004 15:56:03 -0800, David Van Horn wrote:
>   ;; Contract Helpers
>   ;; FIXME: Moving these defns below the provide/contract form causes
>   ;; "reference to an identifier before its definition" errors, which
>   ;; seems like a bug given this is a module.

This isn't a bug (but it may well be a design flaw!). Here's what's
going on: the arguments to -> (and the other contract combinators) are
evaluated eagerly, just like most constructs in Scheme. For example,
this:

  (define my-contract (-> (begin (printf "hi!\n") integer?) integer?))

prints out "hi\n" and then binds my-contract to (-> integer? integer?).
At first glance, it might not make sense why those positions are
arbitrary Scheme code, but it turns out to be critical to get single
point of control for contract definitions themselves.

For example, here's the contract for xexprs:

(define xexpr
  (flat-rec-contract xexpr
    (union symbol?
           string?
           (cons/c symbol 
             (cons/c (listof (list/c symbol? string?))
               xexpr)))))

As you can see, it's not that small. Imagine if you were writing a
function that accepted a produced xepxrs (or even a library of them).
You'd much rather write:

  (provide/contract (f (xexpr . -> . xexpr))
                    (g (xexpr . -> . xexpr))
                    ...)

than have to duplicate that big things each time.

Even better, you can abstract over certain contracts:

  (define (make-alist-contract ele-type)
    (flat-rec-contract alist (union null? (cons/c ele-type alist))))

  (provide/contract [translate ((alist number?) . -> . (alist boolean?))])

So, once we agree we want to have arbitrary expressions in the
arguments to -> and friends, we're pretty much stuck Scheme's technique
for doing mutual references.

Robby


Posted on the users mailing list.