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

From: Neil Toronto (neil.toronto at gmail.com)
Date: Wed Aug 15 09:54:16 EDT 2012

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.
> Thanks for doing this.  I worry a little about re-implementing
> `for/vector`, since now we have two implementations to keep in sync.
> Eventually, I think Typed Racket needs to support more agressive
> inference than it currently does; that's the reality of dealing with a
> macro-generated language.  But for the moment, this would make things
> better for people.

Agree on all counts.

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

> 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.

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.

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.

Neil ⊥

Posted on the dev mailing list.