What does `n` mean in Typed Racket? - racket

n shows up at the type level in error messages, what is it?
Example:
(: trick (All (t u) ((U t (Listof u)) -> (Listof u))))
(define (trick x)
(cond
[(list? x) x]
)
)
Error with this n type:
Type Checker: type mismatch
expected: (Listof u)
given: (U (Listof u) (∩ (Pairof Any (Listof Any)) t)) in: x
I tried writing a type signature with n in it and using go-to-definition in Dr. Racket, but it says the symbol is not found.

it's not n, it's ∩ (intersection).
Thanks #willness and #molbdnilo.

Related

Understanding typechecker behavior around `case->` [duplicate]

For example, how can I write a version of map that will work with polymorphic functions in Typed Racket? I use a simple id function defined as:
(: id : (All (A) A -> A))
(define (id x) x)
When I try to map it over a list i get an error:
> (map id '(1 2 3))
Type Checker: Polymorphic function `map' could not be applied to arguments:
Types: (-> a b ... b c) (Listof a) (Listof b) ... b -> (Listof c)
(-> a c) (Pairof a (Listof a)) -> (Pairof c (Listof c))
Arguments: (All (A) (-> A A)) (List One Positive-Byte Positive-Byte)
Expected result: AnyValues
in: (map id (quote (1 2 3)))
You have to manually instantiate the polymorphism in this case:
-> (map (inst identity Integer) '(1 2 3))
- : (Listof Integer) [more precisely: (Pairof Integer (Listof Integer))]
'(1 2 3)
The reason is explained in the Typed Racket Guide here:
Typed Racket’s local type inference algorithm is currently not able to
infer types for polymorphic functions that are used on higher-order
arguments that are themselves polymorphic.
(see docs for more explanation and examples)

Occurrence typing with polymorphic union types

Suppose I want to convert the following untyped code into typed racket. These functions are inspired by SICP where they show how a data structure can be constructed purely from functions.
(define (make-pair x y)
(lambda (c)
(cond
((= c 1) x)
((= c 2) y)
(error "error in input, should be 1 or 2"))))
(define (first p) (p 1))
(define (second p) (p 2))
To convert it straight to typed racket, the return value of the make-pair function seems to be (: make-pair (All (A B) (-> A B (-> Number (U A B))))). And following this, the type of first should be (: first (All (A B) (-> (-> Number (U A B)) A))). However, while implementing the function we can't call (p 1) directly now because we need some sort of occurrence typing to make sure first returns only of type A. Changing the return type of first to (U A B) works but then the burden of occurrence typing goes on the user and not in the API. So in this scenario how can we use occurrence typing inside first (that is, how to use a predicate for type variable A) so that we can safely return only the first component of the pair?
UPDATE
I tried an approach which differs a bit from above and requires the predicates for A and B to be supplied as arguments to make-pair function. Below is the code:
#lang typed/racket
(define-type FuncPair (All (A B) (List (-> Number (U A B)) (-> A Boolean) (-> B Boolean))))
(: make-pair (All (A B) (-> A B (-> A Boolean) (-> B Boolean) (FuncPair A B))))
(define (make-pair x y x-pred y-pred)
(list
(lambda ([c : Number])
(cond
((= c 1) x)
((= c 2) y)
(else (error "Wrong input!"))))
x-pred
y-pred))
(: first (All (A B) (-> (FuncPair A B) Any)))
(define (first p)
(let ([pair-fn (car p)]
[fn-pred (cadr p)])
(let ([f-value (pair-fn 1)])
(if (fn-pred f-value)
f-value
(error "Cannot get first value in pair")))))
However, this fails in the check (fn-pred f-value) condition with error expected: A
given: (U A B) in: f-value
From the untyped code at the start of your question, it seems like a pair of A and B is a function that given 1, gives back A, and given 2, gives back B. The way to express this type of function is with a case-> type:
#lang typed/racket
(define-type (Pairof A B)
(case-> [1 -> A] [2 -> B]))
The accessors can be defined the same way as your original untyped code, just by adding type annotations:
(: first : (All (A B) [(Pairof A B) -> A]))
(define (first p) (p 1))
(: second : (All (A B) [(Pairof A B) -> B]))
(define (second p) (p (ann 2 : 2)))
The type of the constructor should be:
(: make-pair : (All (A B) [A B -> (Pairof A B)]))
But the constructor doesn't quite work as-is. One thing wrong with it is that your else clause is missing the else part of it. Fixing that gives you:
(: make-pair : (All (A B) [A B -> (Pairof A B)]))
(define (make-pair x y)
(lambda (c)
(cond
[(= c 1) x]
[(= c 2) y]
[else (error "error in input, should be 1 or 2")])))
This is almost right, and if typed racket were awesome enough, it would be. Typed racket treats equal? specially for occurrence typing, but it doesn't do the same thing for =. Changing = to equal? fixes it.
(: make-pair : (All (A B) [A B -> (Pairof A B)]))
(define (make-pair x y)
(lambda (c)
(cond
[(equal? c 1) x]
[(equal? c 2) y]
[else (error "error in input, should be 1 or 2")])))
Ideally occurrence typing should work with =, but perhaps the fact that things like (= 2 2.0) return true makes that both harder to implement and less useful.

How to apply in typed/racket?

In typed/racket I have a case like [(? procedure? p ) (apply p xv*)]
It will cause error:
Type Checker: Function has no cases in: (apply p xv*)
So I write a test case to detect the reason:
#lang typed/racket
(: test-match-apply-0 (-> (-> Any * Any) (Listof Any) Any))
(define test-match-apply-0
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
;; Type Checker: Function has no cases in: (apply p args)
(test-match-apply-0 + (list 1 2 3)) ;; not ok
(apply + (list 2 4)) ;; ok
(: test-match-apply-1 (-> (-> (Listof Any) Any) (Listof Any) Any))
(define test-match-apply-1
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
(test-match-apply-1 + (list 1 2 3)) ;; not ok
;; For int is it right
(: test-match-apply-2 (-> (-> (Listof Any) Any) (Listof Number) Number))
(define test-match-apply-2
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
(test-match-apply-2 + (list 1 2 3)) ;; not ok
(: test-match-apply-3 (-> (-> Number * Number) (Listof Number) Number))
(define test-match-apply-3
(lambda (x args)
(match x
[(? procedure? p) (apply p args)])))
(test-match-apply-3 + (list 1 2 3)) ;; it is ok
I print the + itself:
> (:print-type +)
(case->
(-> Zero)
(-> Number Number)
(-> Zero Zero Zero)
(-> Number Zero Number)
(-> Zero Number Number)
(-> Positive-Byte Positive-Byte Positive-Index)
(-> Byte Byte Index)
(-> Positive-Byte Positive-Byte Positive-Byte Positive-Index)
(-> Byte Byte Byte Index)
(-> Positive-Index Index Positive-Fixnum)
(-> Index Positive-Index Positive-Fixnum)
(-> Positive-Index Index Index Positive-Fixnum)
(-> Index Positive-Index Index Positive-Fixnum)
(-> Index Index Positive-Index Positive-Fixnum)
(->* (Index Index) (Index) Nonnegative-Fixnum)
.....
Come back to my origin needs, How can I make it [(? procedure? p ) (apply p xv*)] possible in typed/racket? Because in the case I can't detect p 's type. Something like type-apply?
The reason Typed Racket can’t apply that procedure is because it knows nothing about it aside from the fact that it is a procedure. It might not take any arguments, for example, in which case that apply would cause a runtime error. It might take a different kind of argument, or it might even have required keyword arguments. TR doesn’t know any of this just from the procedure? predicate succeeding, so it doesn’t allow you to invoke such a value.
This is tricky, because there is no predicate that will allow you to inspect enough details about the function that will make it safe to apply. You basically have two options:
Constrain the type of the input so that procedure? will restrict it to a specific function type. You can do this by making the input a union of specific types. For example, this typechecks:
(: constrained ((U String Number (String * -> String)) -> String))
(define (constrained x)
(match x
[(? string?) x]
[(? number?) (number->string x)]
[(? procedure?) (apply x '("a" "b" "c"))]))
Even though the type is a union type here, since there is only one possible case for which the procedure? predicate is true, TR can restrict the type to a properly applicable value.
The type of the function itself can get pretty fancy, and TR can still figure it out. For example, it still works with a polymorphic type:
(: poly-constrained (All [a] (U String Number (a * -> String)) (Listof a) -> String))
(define (poly-constrained x lst)
(match x
[(? string?) x]
[(? number?) (number->string x)]
[(? procedure?) (apply x lst)]))
Alternatively, you can use cast. This will allow you to tell TR to perform a dynamic check that a value matches a particular type.
(: unconstrained (Any -> String))
(define (unconstrained x)
(match x
[(? string?) x]
[(? number?) (number->string x)]
[(? procedure?) (apply (cast x (String * -> String)) '("a" "b" "c"))]))
However, note that this is a little big dangerous! There are a couple pitfalls to using cast:
The check generates a typed/untyped boundary for a single value, effectively the same sort of boundary between typed and untyped modules. This means that cast generates a contract, which is checked at runtime, which, unlike static types, takes time and can reduce performance significantly if used in a tight loop.
Since cast performs the check dynamically, you lose one of the main benefits of Typed Racket: static type safety. If, for example, someone provides a procedure that does not match the given type, a runtime error will occur, which is precisely the sort of thing Typed Racket is designed to prevent.
If possible, you probably want to use the first approach so that you don’t compromise type safety, but in cases where predicates are not good enough, you can use cast. Just be aware of the downsides before you choose it.

Could not undersand racket function

My proffesor gave us this function:
(: every? : (All (A) (A -> Boolean) (Listof A) -> Boolean))
(define (every? pred lst)
(or (null? lst)
(and (pred (first lst))
(every? pred (rest lst)))))
I couldn't understand the meaning of: All (A) (A -> Boolean).
please can someone can explain to me - what is the meaning of the variable, what the function get, what is it do and what is it return because i can't figure it out.
Let's give the function every? a spin at the repl:
> (every? even? (list 1 2 3 4))
#f
> (every? char? (list #\a #\b #\c))
#t
Note that the type of the first list (list 1 2 3 4) is (Listof Number).
The type of the second list (list #\a #\b #\c) is (Listof Char).
What type should the lst argument of every? have?
Clearly it needs to be a list, but what type are the elements?
We don't know, so we make it a (Listof A), where A stands
for some (unknown) type.
However the predicate pred is called on the elements in the list,
so the type must match. In the first example: even? has the type
"function from number to boolean" aka (A -> Boolean).
In general we need the type: (A -> Boolean) for the predicate.
This becomes:
(: every? : (All (A) (A -> Boolean) (Listof A) -> Boolean))

Typed Racket: Creating generic types with define-type

I'm trying to get a bit into Typed Racket, but I'm having some trouble getting an (admittedly rather constructed) experiment to work.
This is what I originally had:
#lang typed/racket
(: generate-list
(All (A)
((A -> A) (Integer -> A) Integer -> (Listof A))))
(define (generate-list function location-function num-items)
(let: loop : (Listof A)
((count : Integer 0)
(result : (Listof A) (list)))
(if (>= count num-items)
(reverse result)
(loop (+ count 1)
(cons (function (location-function count)) result)))))
; ---------------------------------
(: f (Number -> Number))
(define (f x) (* x x))
(: locf (Integer -> Number))
(define (locf x) x)
; ---------------------------------
(displayln (generate-list f locf 10))
Which has the output:
(0 1 4 9 16 25 36 49 64 81)
Which is nice. Then I figured I could make this a bit better documented by giving the function and location-function a defined type:
#lang typed/racket
(define-type (ListGenFunction A) (A -> A))
(define-type (ListGenLocFunction A) (Integer -> A))
(: generate-list
(All (A)
(ListGenFunction ListGenLocFunction Integer -> (Listof A))))
(define (generate-list function location-function num-items)
(let: loop : (Listof A)
((count : Integer 0)
(result : (Listof A) (list)))
(if (>= count num-items)
(reverse result)
(loop (+ count 1)
(cons (function (location-function count)) result)))))
; ----------- Numbers! ------------
(: f ListGenFunction)
(define (f x) (* x x))
(: locf ListGenLocFunction)
(define (locf x) x)
; ---------------------------------
(displayln (generate-list f locf 10))
Now here's where the problems start (and I really hope some experienced Typed Racketeers aren't facepalming too hard right now). For one, the type checker gives me an error on the line where I define f. The message is rather lengthy, but it's basically: "Type Checker: No function domains matched in function application: Types: ... in: (* x x)". I thought I defined a type that has one parameter of a generic type A that returns a generic type A? Wouldn't (* x x) work? Or is there some need to "tag" the type? (Like in C++-like languages where it's list<int> for example)
On top of that: Now my type-definition for the function generate-list has a return type of "(Listof A)". But that A is not at all declared to be the same A that the parameters with the types ListGenFunction and ListGenLocFunction expect. I kind of want to make that connection, however, so that anyone who uses that function can be sure that the types of his provided functions match the type of the returning list items.
How do I do this correctly?
PS:
I'm not sure if I described my intention in the last paragraph so that anyone can understand it. But if you take some generic pseudo-C++-like code, I want to get the following:
list<T> generate-list(LGF<T> f, LGLF<T> locf, int count) { ... }
So that all T's are exactly the same.
There are two problems here, both of which stem from the same confusion. You're using a generic type, ListGenFunction, without telling Typed Racket (or the reader of your program) what particular type you're using it with.
For example, f isn't an arbitrary ListGenFunction, it's a ListGenFunction that works specifically on numbers. So you should write:
(: f (ListGenFunction Integer))
and
(: locf (ListGenLocFunction Integer))
Similarly, you should give generate-list a type like this:
(: generate-list
(All (A)
((ListGenFunction A) (ListGenLocFunction A) Integer -> (Listof A))))
This is just like how you explicitly say that you're producing a (Listof A), not just a Listof.