[racket] typing a function

From: Neil Toronto (neil.toronto at gmail.com)
Date: Thu Nov 22 10:41:09 EST 2012

On 11/22/2012 07:41 AM, Pierpaolo Bernardi wrote:
> OK, I think I'm not smart enough for TR.

One of my rules is "Never let the computer make you feel stupid." It's 
the computers that are dumb, not the people.

> What's wrong in the following?
> ========
> #lang typed/racket
> (define-type Array2 (Vectorof (Vectorof Number)))
> (: make-array (Positive-Index Positive-Index -> Array2))
> (define (make-array xdim ydim)
>    (for/vector: : Array2 ((i : Positive-Index (in-range xdim)))
>      (make-vector ydim 0)))

With a few tweaks, it works in 5.3.1. It *will not work* in 5.3, because 
we hadn't fixed `for/vector:' yet.

(See? The computer is stupid. It didn't fix the problem for us. :D)

#lang typed/racket

(define-type Array2 (Vectorof (Vectorof Number)))

(: make-array (Positive-Index Positive-Index -> Array2))
(define (make-array xdim ydim)
   (for/vector: : Array2 ((i (in-range xdim)))
     (ann (make-vector ydim 0) (Vectorof Number))))

Here, `ann' means "annotate this expression with this type".

Probably the main trick in working with TR is knowing how and when to 
help it figure out expressions' types. I've learned to avoid giving loop 
variables types, for example. Doing so requires guessing what the 
`in-range' macro expands to. (FWIW, in this case, Nonnegative-Fixnum is 
the most restricted type `i' can have.)

In general, TR has a hard time inferring vector types, because vectors 
are mutable, which means subtyping doesn't work on them. That is, if 
"<:" means "is a subtype of", then this is true:

   (Listof Byte) <: (Listof Integer)

because lists are immutable, but this is NOT true:

   (Vectorof Byte) <: (Vectorof Integer)

In your example program, I've had to tell TR that it's making a vector 
of Number. It had assumed that (make-vector ydim 0) was making a vector 
of Integer, which is not a vector of Number.

One extra thing `for/vector:' has in 5.3.1 is body annotations, and 
using it makes the extra annotation unnecessary:

   (for/vector: ((i  (in-range xdim))) : (Vectorof Number)
     (make-vector ydim 0))

It works because this use of `for/vector:' expands to something that 
annotates the body (make-vector ydim 0) for you.

(Sam and Vincent: this is a nice example of why body annotations are 
better. :D)

To sum up: upgrade, because we made the computer less stupid in 5.3.1, 
and learn a few rules of thumb about when and how to annotate. You're 
doing fine.

One more thing. Are you writing an array library for your own use, or as 
an exercise? The next Racket release will have an array data type.

Neil ⊥

Posted on the users mailing list.