通用类型Map上的F#模式匹配 [英] F# Pattern matching on a generic type Map

查看:77
本文介绍了通用类型Map上的F#模式匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这有效:

// 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

但是我想在类型为Map<'k,'v>的通用Map上进行模式匹配(而不是在诸如Map<string,double>之类的特定类型Map上).用伪代码:

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

但是它不起作用,因为它们都将评估为false

but it does not work as these would both evaluate to false

let testStrDblGen = testGenMap (box dctStrDbl)
let testStrDblGen = testGenMap (box dctStrStr)

我的问题:是否可以在通用Map<'k,'v>上进行匹配?

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

...在这里我可以恢复通用类型'k'v.从这个意义上讲,nilekirk提出的解决方案无法按原样工作.

... where I can recover the generic types 'k and 'v. In that sense, nilekirk's proposed solution would not work as is.

推荐答案

在通用Map上没有内置的模式匹配模式.

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"

这篇关于通用类型Map上的F#模式匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆