Very nice, adding
(: get-user-var (case-> ...))
indeed does the trick. So I can use `case->` to do overloading (if that's what it is called), by defining different functions for different type signatures, and then put them together into a single function via a cond. E.g.:
(: int-add (-> Integer Integer Integer))
(define (int-add x y)
(+ x y))
(: string-add (-> String String String))
(define (string-add x y)
(string-append x y))
(: int-string-add (case->
(-> Integer Integer Integer)
(-> String String String)))
(define (int-string-add x y)
(cond [(integer? x) (int-add x y)]
[(string? x) (string-add x y)]
[else
(error "Not a string or int" x)]))
I am wondering if there is a way to avoid the final definition of `int-string-add`, by simply defining the same function twice (or more) with different type signatures, and then when I call the function, which code gets called depends on the type signature? I would be surprised if this existed in Typed Racket right now, but it would be neat and good to know if there is a more idiomatic/built-in way than what I do above, ie just write:
(: special-add (-> Integer Integer Integer))
(define-special (special-add x y)
(+ x y))
(: special-add (-> String String String))
(define-special (special-add x y)
(string-append x y))
I guess it would be pretty hard, since the type signature has to be coupled more tightly to a specific function than TR requires right now, i.e. I'd have to write (define-special (special-add [x : String] [y : String]) to make the link explicit. Anyway, if it's not possible right now, totally fine.
Regarding refinement types for symbols, I have no idea how useful it would be, as the only example I came up with was the above one, which I think is better dealt with in a different way.
Cheers,
Marc