[racket] problem (?) with typed racket

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Mon Jul 5 10:17:50 EDT 2010

On Jul 5, 2010, at 7:19 AM, Jose A. Ortega Ruiz wrote:

> Hi,
> The following (contrived) typed/racket program doesn't typecheck:
>  (define-struct: (E) Arrow
>    ([arrow : (E -> (Listof E))]))
>  (: compose-arrows (All (E) ((Arrow E) (Arrow E) -> (Arrow E))))
>  (define (compose-arrows a b)
>    (Arrow (lambda (e) ((Arrow-arrow a) (car ((Arrow-arrow b) e))))))

As Noel points out, all that's missing is a type declaration for 
the parameter e in the lambda: 

 (lambda ({e : E}) ...)

will do the trick. 

Why? TR does not infer types. It checks them. When a type declaration
is missing, TR assumes that e is of type TheRacketType, aka Any. For 
a parameter of type Any, it makes no sense to be used in a position 
where it is supposed to be a number, a boolean, or an E. Your program
must somehow 'narrow' the type of e down to what the operation expects, 
in your case E. 

If I knew where the TR guide lives, I'd add the appropriate two-line 
paragraph to clarify this point. 

;; --- 

> Is the failure to type check a genuine limitation of the type inference
> engine, or is it me expecting too much from type inference in general?
> And, is there a more compact way of indicating the type of that lambda?

It is not quite true that TR doesn't infer types. It does so but in 
an extremely limited manner. Technically, this is called LOCAL Inference. 

What does this mean? 

When you write (lambda (x) ...) TR can't know what this function will be 
applied to. It must really assume x ranges over Any. 

When you write (let ((x 7)) ...) however, TR assumes you want x to range 
over numbers in the body of let because the initial value has type Number. 
To see how this fails, try 

 (let ([x 7]) (set! x "hello") x)

Again, I wish I could clarify this bit in the docs. 

-- Matthias

Posted on the users mailing list.