Пытаясь понять активные шаблоны F#, почему я могу это сделать:

у меня есть Dictionary над которым я изначально повторил таким образом:

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

позже я обнаружил, что могу использовать KeyValue активный шаблон, и сделать это:

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

зная, что активные шаблоны не являются какой-то формой директивы препроцессора, как я могу заменить kvp аргумент в лямбде для функции, которая разлагает его?

2 ответов


функции аргументы вызова всегда разрушаются с помощью сопоставления шаблонов. Например:

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

семантически, fun-> примерно эквивалентно

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


Я думаю, что ответ от @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. The match construct немного более мощный, потому что вы можете указать несколько предложений.

теперь активные шаблоны не действительно волшебно. Это просто обычные функции со специальными названиями. Компилятор ищет активные шаблоны в области, когда находит именованный шаблон. Например, шаблон, который вы используете, - это просто функция:

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 )