Question

I have a Dictionary over which I initially iterated thusly:

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

Later, I discovered that I could make use of the KeyValue active pattern, and do this:

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

Knowing that active patterns aren't some form of preprocessor directive, how am I able to substitute the kvp argument in the lambda for a function that decomposes it?

Was it helpful?

Solution

Functions arguments call always be destructured using pattern matching. For instance:

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 to

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

OTHER TIPS

I think the answer from @kvb covers in enough details why you can use patterns in the arguments of fun. This is not an ad-hoc feature - in F#, you can use patterns anywhere where you can bind a variable. To show some of the examples by @kvb in another 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 multiple clauses.

Now, active patterns are not really that magical. They are just normal functions with special names. The compiler searches for active patterns in scope when it finds a named pattern. For example, the pattern you're using is just a function:

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

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

myDictionary |> Seq.iter (fun _arg0 ->
  let _arg1 = (|KeyValue|) _arg0
  let (k, v) = _arg1 
  doSomething k v )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top