Let me propose a simpler (in some ways) type for your example:
(: odds-on (All (X Y) (X Y Real -> (U X Y))))
(define (odds-on choice alternative odds)
(cond [(< (random) odds) choice]
[else alternative]))
and using it like this:
-> ((odds-on (lambda () (displayln "hi"))
(lambda () (displayln "bye"))
0.75))
bye
-> ((odds-on (lambda ([x : String]) (string-append x "1"))
(lambda ([x : String]) (string-append x "2"))
0.23)
"test")
- : String
"test2"
There's a bit of a tradeoff here though, since now you can pass odds-on
things that aren't actually functions. If you do happen to pass odds-on
some non-function values, you won't be able to call the returned value though (i.e., the type-checker will catch it later anyway).
(Note: as an aside, if Typed Racket supported bounded polymorphism you would be able to express a constraint that X
and Y
must be functions in this example. That's potentially future work for TR.)
There's also the (U X Y)
in the return type that you have to be careful about. If you pass odds-on
two functions with incompatible argument arities, it will be more difficult to call the resulting function.
-> ((odds-on (lambda () (displayln "hi"))
(lambda (x) (displayln "bye"))
0.75))
; readline-input:10:0: Type Checker: could not apply function;
; wrong number of arguments provided
; expected: 1
; given: 0
; in: ((odds-on (lambda () (displayln "hi")) (lambda (x) (displayln "bye"))
; 0.75))
; [,bt for context]
(Note: your error message may look different. I'm running Racket v6.0.0.4. Also, this error message is not so great.)