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