<div dir="ltr">Oh, I see. Yes, even better.<div><br></div><div>Robby</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Jan 6, 2013 at 4:36 PM, Sam Tobin-Hochstadt <span dir="ltr"><<a href="mailto:samth@ccs.neu.edu" target="_blank">samth@ccs.neu.edu</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Right -- if we (the typed code) are picking the instantiation, then we<br>
have to check structurally, to make sure that it's really got integers<br>
everywhere.<br>
<br>
But if it's a plain type parameter, then the untyped side gets to pick<br>
it, and WLOG they could pick `Any`, meaning that there's no wrong<br>
values they could supply. That means that as long as they supply a<br>
`kons`, it must meet the contract of `(Kons A)`. So I think the<br>
contract can be much cheaper in this one specific case, which<br>
fortunately is the case that Neil cares about, I think.<br>
<br>
Sam<br>
<br>
On Sun, Jan 6, 2013 at 5:28 PM, Robby Findler<br>
<div class="HOEnZb"><div class="h5"><<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>> wrote:<br>
> Oh-- I think you're right that the type parameter can matter (it could go<br>
> over to R as an Integer list and come back as a Boolean list or something).<br>
><br>
> Robby<br>
><br>
><br>
> On Sun, Jan 6, 2013 at 4:08 PM, Sam Tobin-Hochstadt <<a href="mailto:samth@ccs.neu.edu">samth@ccs.neu.edu</a>><br>
> wrote:<br>
>><br>
>> Sorry, that was very silly of me. That isn't what's happening at all,<br>
>> because type soundness means we don't need to enforce the<br>
>> parametricity at all.<br>
>><br>
>> The actual relevant program is:<br>
>><br>
>> (module m racket<br>
>> (struct kons (a d))<br>
>> (struct mt ())<br>
>> (define MT (mt))<br>
>> (define (FST v)<br>
>> (when (eq? MT v) (error 'empty))<br>
>> (kons-a v))<br>
>> (define (RST v)<br>
>> (when (eq? MT v) (error 'empty))<br>
>> (kons-d v))<br>
>> (define (LST . x)<br>
>> (if (empty? x)<br>
>> MT<br>
>> (kons (first x) (apply LST (rest x)))))<br>
>> (define (LST/C elem/c)<br>
>> (define C (recursive-contract<br>
>> (or/c (λ (v) (eq? v MT))<br>
>> (struct/dc kons [a elem/c] [d C]))))<br>
>> C)<br>
>> (provide/contract<br>
>> [LST (->* () #:rest any/c (LST/C any/c))]<br>
>> [FST (-> (LST/C any/c) any/c)]<br>
>> [RST (-> (LST/C any/c) (LST/C any/c))])<br>
>> )<br>
>><br>
>> However, thinking about this more, it's an invariant that `kons`<br>
>> structures are always correctly constructed, and we can rely on them<br>
>> to have *some* instantiation that typechecks -- that's why the `any/c`<br>
>> is ok. That suggests to me that contract generation for a struct type<br>
>> applied to simple type variables can always be just the predicate for<br>
>> that type, which would make Neil very happy. I want to think about<br>
>> this more before I'm sure, though.<br>
>><br>
>> Thanks for being patient while I get this wrong in various ways ...<br>
>> Sam<br>
>><br>
>> On Sun, Jan 6, 2013 at 4:13 PM, Robby Findler<br>
>> <<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>> wrote:<br>
>> > This has a non-chaperone contract being used in a struct/c, I think?<br>
>> ><br>
>> > (FST (LST 1 2 3)) => struct/dc: expected chaperone contracts, but field<br>
>> > a<br>
>> > has #<barrier-contract><br>
>> ><br>
>> > Robby<br>
>> ><br>
>> ><br>
>> > On Sun, Jan 6, 2013 at 2:40 PM, Sam Tobin-Hochstadt <<a href="mailto:samth@ccs.neu.edu">samth@ccs.neu.edu</a>><br>
>> > wrote:<br>
>> >><br>
>> >> On Sun, Jan 6, 2013 at 3:23 PM, Robby Findler<br>
>> >> <<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>> wrote:<br>
>> >> > On Sun, Jan 6, 2013 at 2:18 PM, Sam Tobin-Hochstadt<br>
>> >> > <<a href="mailto:samth@ccs.neu.edu">samth@ccs.neu.edu</a>><br>
>> >> > wrote:<br>
>> >> >><br>
>> >> >> > The boundaries have the information; that's how the contracts got<br>
>> >> >> > inserted<br>
>> >> >> > in the first place.<br>
>> >> >><br>
>> >> >> No, the contracts are parametric contracts using `parametric->/c`,<br>
>> >> >> and<br>
>> >> >> thus don't have any information about the types used at all.<br>
>> >> ><br>
>> >> ><br>
>> >> > I don't see why you can't tag them when something at a boundary and<br>
>> >> > then<br>
>> >> > check that something at another boundary instead of doing some deep<br>
>> >> > check.<br>
>> >><br>
>> >> The problem is that I don't know what to tag them *with*.<br>
>> >><br>
>> >> Consider the following program:<br>
>> >><br>
>> >> #lang racket<br>
>> >><br>
>> >> (struct kons (a d))<br>
>> >> (struct mt ())<br>
>> >> (define MT (mt))<br>
>> >> (define (FST v)<br>
>> >> (when (eq? MT v) (error 'empty))<br>
>> >> (kons-a v))<br>
>> >> (define (RST v)<br>
>> >> (when (eq? MT v) (error 'empty))<br>
>> >> (kons-d v))<br>
>> >> (define (LST . x)<br>
>> >> (if (empty? x)<br>
>> >> MT<br>
>> >> (kons (first x) (apply LST (rest x)))))<br>
>> >> (define (LST/C elem/c)<br>
>> >> (define C (recursive-contract<br>
>> >> (or/c (λ (v) (eq? v MT))<br>
>> >> (struct/c kons elem/c C))))<br>
>> >> C)<br>
>> >> (provide/contract<br>
>> >> [LST (parametric->/c (A) (->* () #:rest A (LST/C A)))]<br>
>> >> [FST (parametric->/c (A) (-> (LST/C A) A))]<br>
>> >> [RST (parametric->/c (A) (-> (LST/C A) (LST/C A)))])<br>
>> >><br>
>> >> This is the essence of Neil's polymorphic list program, as implemented<br>
>> >> by Typed Racket. I don't know how to change those contracts to not be<br>
>> >> really expensive, because I can't pick the instantiation of A at<br>
>> >> runtime to tag the structure instances with.<br>
>> >><br>
>> >> Sam<br>
>> ><br>
>> ><br>
><br>
><br>
</div></div></blockquote></div><br></div>