[racket-dev] Wrapping loops for TR isn't working, and the type annotations are for the wrong value

From: Sam Tobin-Hochstadt (samth at ccs.neu.edu)
Date: Wed Aug 15 10:05:47 EDT 2012

On Wed, Aug 15, 2012 at 9:54 AM, Neil Toronto <neil.toronto at gmail.com> wrote:
> On 08/15/2012 05:24 AM, Sam Tobin-Hochstadt wrote:
>> On Tue, Aug 14, 2012 at 11:52 PM, Neil Toronto <neil.toronto at gmail.com>
>> wrote:
>>> Some typed "for" loops would have to be reimplemented, unless inference
>>> improves a lot. To make this easier, I've attached an example
>>> implementation
>>> of `for/vector:' and `for*/vector:'. It allows both body and result
>>> annotations, handles #:length properly, allows #:when clauses anywhere,
>>> and
>>> fixes the two bugs in `for/vector' I reported today.

> BTW, what do you think of deprecating result annotations and using body
> annotations instead?

I'm not sure yet.

>> Two questions: (1) how similar is the generated code to the expansion
>> of plain `for/vector`[?]...
> In the case where #:length is missing, not very. I couldn't use `for/list:'
> and convert to a vector because I couldn't reliably generate (Listof T) from
> the result type (because of type aliases). On the plus side, mine's about
> twice as fast. It expands to plain `for:' and bangs values into a growable
> vector.

In that case, presumably we should change `for/vector` in
`racket/base` to the faster version.

Matthew, does this seem reasonable?

> When #:length is given, it's similar in that it creates a vector outside the
> loop and bangs values into it. But I have to start with (define vs (vector))
> and then (set! vs (make-vector n v)) when the first value `v' is computed.
> The docs for `for/vector' say any values not computed in the loop are
> supposed to be 0, but that doesn't work well in TR: it'd have to create a
> (Vectorof (U T 0)). Ick.

So then the first value computed is replicated everywhere?  That seems
unappealing as well.

Also, is there any way you could generate code that uses a binding,
instead of `set!`?  That will probably improve the performance.

> I wouldn't mind if `for/vector' behaved the same way, since the current
> behavior makes it easy to violate contracts. On my computer, my
> `for/vector:' with #:length takes only 5% longer to run than an equivalent
> `for/vector' loop with moderate-sized vectors.
>> and (2) would it be possible to abstract the implementation of
>> Racket's `for/vector` to allow you to re-use some of that code here?
> I wouldn't want to because `for/vector' is currently broken when #:length is
> given. (See PR 13029 and PR 13030.)
> I think the only way to fix it is to implement it like I did: expand to
> plain `for:' and mutate an external index. So it might be better to have
> them share a new common implementation.


> I think I could work one up that expands to code with annotations when used
> from TR and to code without annotations otherwise. I'd use the
> "maybe-annotate" macro (`ann:') for every annotation, not just for
> annotating with the optional result and body types.

I don't think that's a good idea -- then `racket/base` would have to
expand to Typed Racket-specific code.  Is there a way that you can
come up with an abstraction that is oblivious to Typed Racket?
sam th
samth at ccs.neu.edu

Posted on the dev mailing list.