Reputation: 999
This works :
// sample objects
let dctStrDbl = [("k1",1.0); ("k2",2.0)] |> Map.ofList
let dctStrStr = [("k1","v1"); ("k2","v2")] |> Map.ofList
let lstMisc = [1; 2; 3]
let testStrDbl (odico : obj) : bool =
match odico with
| :? Map<string,double> as d -> true
| _ -> false
let testTrue = testStrDbl (box dctStrDbl) // this evaluates to true
let testFalse = testStrStr (box dctStrStr) // this evaluates to false
let testMiscFalse = testStrDbl (box lstMisc) // evaluates to false
However I would like to pattern match on a generic Map of type Map<'k,'v>
(rather than on a specific type Map like Map<string,double>
). In pseudo-code :
let testGenMap (odico : obj) : bool =
match odico with
| :? Map<'k,'v> as d -> true
| _ -> false
but it does not work as these would both evaluate to false
let testStrDblGen = testGenMap (box dctStrDbl)
let testStrDblGen = testGenMap (box dctStrStr)
My question : is there a way to match on a generic Map<'k,'v>
?
= EDIT =======
Maybe I should have given some extra context. What I am truly after is something like this
let findGen (odico : obj) (defVal : 'a) (apply : (Map<'k,'v> -> 'a)) : 'a =
match odico with
| :? Map<'k,'v> as d -> apply d
| _ -> defVal // the object is not of the expected type
... where I can recover the generic types 'k
and 'v
. In that sense, nilekirk's proposed solution would not work as is.
Upvotes: 0
Views: 354
Reputation: 2383
There is no built-in way to pattern match on a generic Map.
What you can do is use reflection and an active pattern:
let (|IsMap|_|) (x: obj) =
if x.GetType().Name.StartsWith("FSharpMap") then Some () else None
let test = function
| IsMap -> true
| _ -> false
Map.empty<int,string> |> test // true
[1] |> test // false
= EDIT =======
Seeing your edit above, maybe the following will work:
let isMap<'k,'v when 'k : comparison> (m: obj) =
typeof<Map<'k,'v>> = m.GetType()
let findGen odico defVal (apply : Map<'k,'v> -> 'a) =
if odico |> isMap<'k,'v> then
odico |> unbox<Map<'k,'v>> |> apply
else
defVal
let apply (x: Map<int,string>) = "the apply result"
findGen ([1,"one"] |> Map.ofList) "defVal" apply // "the apply result"
findGen (["one",1] |> Map.ofList) "defVal" apply // "defval"
findGen [1] "defVal" apply // "defval"
Upvotes: 1