[plt-scheme] Re: function contracts

From: Robby Findler (robby at cs.uchicago.edu)
Date: Fri Mar 12 17:20:54 EST 2004

At Fri, 12 Mar 2004 13:41:58 -0500, David Van Horn wrote:
>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme
> Robby Findler wrote:
> > You need to use ->*, put the arguments into the list part and check the
> > length of the list manually, for now. 
> In this case the function must be defined to take any number of
> arguments, but I'd like to provide such a contract on a procedure of
> arity 2 without changing the procedure's definition. Is this
> possible?
> For example, consider a variant of srfi 1's zip that is defined only for two 
> lists, which must be of equal length.
>     (define (zip2 ls1 ls2) (map list ls1 ls2))

Right you are. It's not possible.

I've just added a new contract combinator called ->r (r for "related"
as in "the arguments are related to each other"). It is available in
the exp-tagged code. The docs are in an inconsistent state at the
moment, so I've put the raw form of the docs below.

As an example, here's a contract for zip:

(define (same-length x) (flat-contract (lambda (y) (= (length x) (length y)))))

(->r ([x (listof any?)] 
      [y (and/c (listof any?) (same-length x))])
     (and/c (listof any?) (same-length x)))

It says that the function takes in two arguments and that inputs are
two lists of numbers, with the second list's length being equal to the
first lists's length. It also says that the result must be the same
length as the first input list.


(-> ([id expr] ...) expr)

The \scheme|->r| contract allows you to build a contract
where the arguments to a function may all depend on each
other and the result of the function may depend on all of
the arguments. 

Each of the \scheme|id|s names one of the actual arguments
to the function with the contract. Each of the names is
available to all of the other contracts. For example, to
define a function that accepts three arguments where the
second argument and the result must both be between the
first, you might write:

(->r ([x number?] [y (and/c (>=/c x) (<=/c z))] [z number?])
     (and/c number? (>=/c x) (<=/c z)))

(-> ([id expr] ...) id expr expr)

This form of the \scheme|->r| contract is just like the
previous one, except that the functions it matches must
accept arbitrarily many arguments. The extra \scheme|id|
and the \scheme|expr| just following it specify the
contracts on the extra arguments. The value of \scheme|id|
will alway be a list (of the extra arguments).

Posted on the users mailing list.