I am trying to define the type annotation for the following function in Typed Racket:
(define (neof x)
(if (eof-object? x) #f x))
Leaving it un-annotated gives the type:
(Any -> Any)
Using this type produces an error:
(: neof (All (A) (case->
(EOF -> False)
(A -> A : #:+ (! EOF))))
expected: A
given: False
in: #f
This is presumably because one can let A = EOF
and then we get EOF -> EOF
.
The type (: neof (All (A) A -> (U A False) #:- (U EOF False)))
, while not as clear as the above, also gives errors:
mismatch in filter
expected: (Top | Bot)
given: ((! (U False EOF) @ x) | ((U False EOF) @ x))
in: (if (eof-object? x) #f x)
My goal was to have a function which I could apply to any output from a port an get either False
or the value from the port. I am now reconsidering the need for this, as I've blown way too much time trying to figure out this type.
For completeness, I also tried this definition of neof
:
(define/match (neof x)
[((? eof-object?)) #f]
[((? (compose not eof-object?))) x])
(Also with the second pattern being _
, but that doesn't encode the same amount of type information. At this point I'm more trying to appease the type checker than anything).
So: how can I represent the type of neof
?
I think the type you want is this:
(: neof (All (A) (A -> (U False A) :
#:+ (! EOF)
#:- (or EOF False))))
(The #:-
clause is optional, I just included it there for completeness.)
Note: If the #:-
clause is included, it will not typecheck in Racket 6.1.1. Removing the clause will allow it to pass on 6.1.1.
The issue here is that all branches of case->
must typecheck independently of one another. For the (A -> A)
case, it fails because #f
is not an A
. The occurrence typing information from the first case cannot influence typechecking on the second case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With