[plt-scheme] Contracts

From: Matt Jadud (mcj4 at kent.ac.uk)
Date: Wed Jul 12 05:49:34 EDT 2006

I've never really used the contract system; however, I figure Robby and 
others have probably spent a lot of time making them work, so I should 
consider using them. That, and my code might be safer/more 
robust/self-documenting/colorfast in hot water.

Although this is just an example, the first function I happened try and 
write a contract for was recursive. It wasn't 'fact', but that's OK.

(define/contract fact
     (number? . -> . number?)
     (lambda (n)
       (if (zero? n)
           1
           (* n (fact (sub1 n))))))

This dies. I skimmed a tech report by Robby and Matthias re: HO 
contracts, and see why this is problematic.

This, of course, works:

(module just-the-facts mzscheme
   (require (lib "contract.ss"))
   (provide/contract (fact (-> number? number?)))

   (define (fact n)
     (if (zero? n)
         1
         (* n (fact (sub1 n))))))

Welcome to DrScheme, version 350.
Language: Textual (MzScheme, includes R5RS).
 > (require just-the-facts)
 > (fact 5)
120
 > (fact 'a)
6:3: top-level broke the contract (-> number? number?) on fact; expected 
<number?>, given: a

Now, a question about the design of modules with contracts. I don't know 
what kind of overhead contracts place on code: I assume it is either 
minimal, or noteworthy (meaning "enough that it might matter"). 
Therefore, it is common or bad practice to write code like:

(module just-fact mzscheme
   (provide fact)
   (define (fact n)
     (if (zero? n)
         1
         (* n (fact (sub1 n))))))

(module fact-with-contract mzscheme
   (require (lib "contract.ss"))
   (require just-fact)
   (provide/contract (fact (-> number? number?))))

(module fact-without-contract mzscheme
   (require just-fact)
   (provide fact))

Assuming that this code gets used like:

Welcome to DrScheme, version 350.
Language: Textual (MzScheme, includes R5RS).
 > (require (prefix fwc: fact-with-contract))
 > (fwc:fact 5)
120
 > (fwc:fact 'a)
6:3: top-level broke the contract (-> number? number?) on fwc:fact; 
expected <number?>, given: a
 > (require (prefix fw/oc: fact-without-contract))
 > (fw/oc:fact 5)
120
 > (fw/oc:fact 'a)
. zero?: expects argument of type <number>; given a

That is, the module with contracts and the module without contracts 
provide identical exports, but one attaches contracts to the exports, 
while the other does not.

I can think of plenty of reasons why this is not a good idea; are there 
any reasons it is a good idea, and does anyone use the module/contract 
system this way in practice?

Cheers,
M


Posted on the users mailing list.