[plt-dev] Re: [plt-scheme] New contract-related features

From: Stevie Strickland (sstrickl at ccs.neu.edu)
Date: Sun Feb 15 15:02:09 EST 2009

On Feb 15, 2009, at 2:24 PM, Matthias Felleisen wrote:
> Could we improve the error message for people who attempt to nest  
> regions
>
>> #lang scheme
>>
>> (with-contract f1
>>              ((y number?))
>>              (with-contract f2
>>                             ((x boolean?))
>>                             (define x #t)
>>                             (define y 1)))

I know about this error, and it's on my list to figure out what's  
causing it.  I imagine it's something in the expansion.  However, one  
issue here even if I do fix the problem is that you're defining y  
inside the scope of a with-contract but not exporting it, so your  
definition should be:

(with-contract f1
  ((y number?))
  (with-contract f2
    ((x boolean?))
    (define x #t))
  (define y 1))

Now, whether

(with-contract f1
  ((y number?))
  (with-contract f2
    ((x boolean?) y)
    (define x #t)
    (define y 1)))

should work is a good question, and I'm not sure.  The problem is that  
by the point of the outer with-contract, you've already converted the  
definition of y to an inner definition and a rename-transformer bound  
to the syntax y, and... yeah.  It's nice to just require the  
definition being contracted to appear within the with-contract  
directly, but I'm not opposed to other ideas about how to handle it.

Note that the following *will* work:

(with-contract f1
  ((y number?))
  (define y
    (begin
      (with-contract f2
        ((x boolean?))
        (define x #t))
      1)))

If you just want to contract x as you use it in y's definition.  It's  
just the direct with-contract/with-contract nesting that fails, and I  
expect it's still some detail of the expansion process that I'm  
forgetting to take into account.  It should work though, so I do plan  
on fixing this, as you might like to do something like the following:

(with-contract f1
  ((y number?)
   (z string?))
  (begin
    (with-contract f2
      ((x boolean?))
      (define x #t))
    (define y 1)
    (define z "world")))

Where the internal, protected version of x is available to multiple to- 
be-protected
definitions.

I imagine this is due to some lingering issues in expansion.  Matthew  
helped me out with some before when I was trying to head-expand  
everything and helped me realize what I wanted to do, but I didn't get  
all of them before I switched over to getting unit contracts  
implemented.

> or
>
>> #lang scheme
>>
>> (define (f x)
>> (with-contract
>>  f1
>>  ((y number?))
>>  (define y x)))
>>
>> (f 10)

The error you're getting here is coming from the implicit begin from  
the definition, because with-contract forms are not expressions (since  
they just define names) and thus the begin still needs one.  Your  
definition of f doesn't have a body, just the (protected) internal  
definition of y.

It's the same error you'd get from something like:

(define (f x)
(define-unit U@
  (import)
  (export)))

where the internal forms have been expanded completely, in case they  
do end up providing at least one body expression, but it turns out  
they didn't.

So if you do provide a body expression for f's definition:

(define (f x)
(with-contract
  f1
  ((y number?))
  (define y x))
(+ x 3))

(f 10)

it works fine.

Stevie


Posted on the dev mailing list.