Apologies for the messy title—my technical vocab is lacking, and I was unsure of how to phrase this. How can I identify an argument in Racket as being of a certain type, without knowing either
match
)type?
(such as integer?
) that checks if it is the specified type?Specifically, imagine I have some function with the type (: fn : (All (a b c) (a -> c) (b -> c) (Listof (U a b)) -> Listof c))
; we can imagine it being called as (fn fa fb xs)
. I would like this function to convert xs
into a Listof c
; it should do so by mapping each element x
of xs
to (fa x)
if x
is of type a
, and (fb x)
if x
is of type b
. For example, we might take in a list of strings and reals, and map the strings to their lengths, and the reals to the nearest integers.
In the specific case where I know that a
is String
and b
is Real
, I can write something like
(define (fn fa fb xs)
(map (lambda (x) (if (string? x) (fa x) (fb x))) xs))
But this works only if I have a known function string?
to check the type of x
.
Is it possible to do what I'm suggesting in Racket?
There's no "type of" operation in Typed Racket, so the answer is no. However, you can pass a "decider" to fn
to select which function should be used to apply for each element.
The ->
form allows you to specify propositions for occurrence typing, so you can write this code:
#lang typed/racket
(: fn (All (a b c)
((U a b) -> Boolean : a)
(a -> c)
(b -> c)
(Listof (U a b))
->
(Listof c)))
(define (fn decider fa fb xs)
(map (lambda ([x : (U a b)])
(if (decider x) (fa x) (fb x)))
xs))
Then you can invoke it:
(fn string? string-length add1 (list 1 "a" 23 "bc"))
;; '(2 1 24 2)
Thanks to Sam Tobin-Hochstadt for his help!