Trying to understand the active F # templates, why can I do this:

I have a Dictionary that I iterated over initially:

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

Later I discovered that I could use the active KeyValue template and do this:

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

Knowing that active templates are not some form of preprocessor directive, how can I substitute the kvp argument into lambda for a function that decomposes it?

+7
source share
2 answers

Signs of function arguments should always be destructed using pattern matching. For example:

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

Semantically, fun <pat> -> <body> is roughly equivalent

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

+14
source

I think the answer from @kvb describes in sufficient detail why you can use templates in fun arguments. This is not a special function - in F # you can use templates wherever you can bind a variable. To show some @kvb examples in other contexts:

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

Similarly, you can use patterns when writing fun . The match construct is a bit more powerful because you can specify a few sentences.

Now active templates are not really magical. These are ordinary functions with special names. The compiler searches for active templates in scope when it finds a named template. For example, the template you use is just a function:

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

The sample turns the KevValuePair object into a regular F # tuple, which is then matched by a nested pattern (k, v) (which assigns the first element k and the second to v ). The compiler essentially translates your code into:

 myDictionary |> Seq.iter (fun _arg0 -> let _arg1 = (|KeyValue|) _arg0 let (k, v) = _arg1 doSomething kv ) 
+5
source

All Articles