Пытаясь понять активные шаблоны 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 )