9

我有一个Dictionary我最初这样迭代的:

myDictionary |> Seq.iter (fun kvp -> doSomething kvp.Key kvp.Value)

后来,我发现我可以利用KeyValue活动模式,并这样做:

myDictionary |> Seq.iter (fun (KeyValue (k, v)) -> doSomething k v)

知道活动模式不是某种形式的预处理器指令,我如何能够kvp将 lambda 中的参数替换为分解它的函数?

4

2 回答 2

16

函数参数调用总是使用模式匹配进行解构。例如:

let getSingleton = fun [x] -> x
let getFirst = fun (a,b) -> a
let failIfNotOne = fun 1 -> ()
let failIfNeitherOne = fun (x,1 | 1,x) -> ()

从语义上讲,fun<pat> -><body> 大致等价于

fun x ->
match x with
|<拍> -><身体>
| _ -> raise MatchFailureException(...)

于 2012-11-27T18:16:52.213 回答
6

我认为@kvb 的答案涵盖了足够详细的信息,为什么您可以在fun. 这不是一个特别的功能 - 在 F# 中,您可以在任何可以绑定变量的地方使用模式。要在其他上下文中显示@kvb 的一些示例:

// When declaring normal functions     
let foo [it] = it    // Return the value from a singleton list
let fst (a, b) = a   // Return first element of a pair

// When assigning value to a pattern using let
let [it] = list
let (a, b) = pair

同样,您可以在编写时使用模式fun。该match结构更强大一些,因为您可以指定多个子句。

现在,主动模式并没有那么神奇。它们只是具有特殊名称的普通函数。编译器在找到命名模式时搜索范围内的活动模式。例如,您使用的模式只是一个函数:

val (|KeyValue|) : KeyValuePair<'a,'b> -> 'a * 'b

该模式将KevValuePair对象转换为普通的 F# 元组,然后由嵌套模式匹配(k, v)(将第一个元素分配给k,将第二个元素分配给v)。编译器基本上将您的代码转换为:

myDictionary |> Seq.iter (fun _arg0 ->
  let _arg1 = (|KeyValue|) _arg0
  let (k, v) = _arg1 
  doSomething k v )
于 2012-11-27T18:43:25.190 回答