[racket] contracts on liberal function inputs: avoiding duplicate effort

From: Matthew Butterick (mb at mbtype.com)
Date: Mon Nov 18 15:44:46 EST 2013

> To ensure that an input string represents a valid address, the contract
> needs to parse the string. The constructor for the address structure
> also needs to parse the string to get the data, so it's redundant.
> 
> (I didn't come up with a nice solution though)


BTW it's not that I want to abuse contracts — on the contrary, contracts are such a handy & distinctive idiom that I keep wanting to fold more of my input & output processing into them. For instance, I've thought about creating a pattern like this:

(define/lambda-contract (f x)
  (in/lc . -> . out/lc)
  (do-stuff-to x))

That expands into something like this:

(out/lc (do-stuff-to (in/lc x))

Where each "lambda contract" embodies both a data-conversion step and traditional contract-checking step:

(define in/lc (lambda (x) (in-processing (in/c x))))
(define out/lc (lambda (x) (out/c (out-processing x))))

So (f x) ultimately evaluates to this:

(out/c (out-processing (do-stuff-to (in-processing (in/c x)))))

The contracts are still at the function boundaries, where they need to be.

But there's an obvious problem on the input side, because in-processing wants x, not the result of (in/c x).

(And probably other obvious problems I'm not considering, because I haven't figured out how to cure that one.)

Posted on the users mailing list.