Suzanne Soy
Suzanne Soy

Reputation: 3244

Bounded parameterized types with typed/racket

Let's say I have a function operating on values of type base and returning values of type base:

(struct base ([x : Real]))
(struct child base ([y : String]))

(: fun (base base → base))
(define (fun a b)
  (if (> (base-x a) (base-x b))
      a
      b))

The function fun can also be restricted to the type child, in which case it is guaranteed to return values of type child (without modifying the code):

(: fun (child child → child))

One can also make it accept base or child values, and return the same type:

(: fun (case→ (base base → base)
              (child child → child)))

This lacks the bound, and fails for obvious reasons:

(: fun (All (T) (T T → T)))

How can I simplify this when there are many child types, by providing a bound to All?

I'm looking for some syntax similar to this one:

(: fun (All (T : base) (T T → T)))

Upvotes: 2

Views: 92

Answers (1)

Alex Knauth
Alex Knauth

Reputation: 8373

That's not supported directly, but in the latest snapshot versions, it's possible to simulate that with intersection types:

(: fun : (All (T) ((∩ base T) (∩ base T) → (∩ base T))))

Then fun returns the most specific type it can when given mixes of base and child types:

> (fun (base 1) (base 2))
- : base
#<base>
> (fun (base 1) (child 2 "string"))
- : base
#<child>
> (fun (child 1 "string") (base 2))
- : base
#<base>
> (fun (child 1 "string") (child 2 "string"))
- : (∩ child base)
#<child>
> (ann (fun (child 1 "string") (child 2 "string")) child)
- : child
#<child>

And you can use a (∩ child base) in a context that expects a child.

Upvotes: 1

Related Questions