试图理解F#活动模式,为什么我可以这样做:

Mil*_*oDC 8 f# active-pattern

我有一个Dictionary我最初迭代,因此:

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

后来,我发现我可以使用KeyValue活动模式,并执行此操作:

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

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

kvb*_*kvb 15

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

let getSingleton = fun [x] -> x
let getFirst = fun (a,b) -> a
let failIfNotOne = fun 1 -> ()
let failIfNeitherOne = fun (x,1 | 1,x) -> ()
Run Code Online (Sandbox Code Playgroud)

从语义上讲,fun<pat> -><body>大致相当于

fun x ->
match x with
|<pat> -><body>
| _ -> raise MatchFailureException(...)


Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

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

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

val (|KeyValue|) : KeyValuePair<'a,'b> -> 'a * 'b
Run Code Online (Sandbox Code Playgroud)

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

myDictionary |> Seq.iter (fun _arg0 ->
  let _arg1 = (|KeyValue|) _arg0
  let (k, v) = _arg1 
  doSomething k v )
Run Code Online (Sandbox Code Playgroud)

  • 并不是所有地方......至少`use`绑定和成员声明中的`this`标识符被限制使用正确的标识符而不是模式,遗憾的是. (4认同)
  • @kvb真实而真实.也不适用于隐式构造函数类中的`as self`.我相信这是唯一的三个案例,实际上这个名称的含义. (4认同)