Improve my nested matches in F# [duplicate] - f#

This question already has answers here:
Getting rid of the "pyramid of doom" in F#
(2 answers)
Closed 5 years ago.
Suppose I want to do repeated map lookups.
In C#, I can use return for a "flat" control-flow:
Thing v = null;
if (a.TryGetValue(key, out v))
{
return v;
}
if (b.TryGetValue(key, out v))
{
return v;
}
if (c.TryGetValue(key, out v))
{
return v;
}
return defaultValue;
It's a bit ugly, but quite readable.
In F#, which I am less familiar with, I would use match expressions:
match a.TryGetValue(key) with
| (true, v) -> v
| _ ->
match b.TryGetValue(key) with
| (true, v) -> v
| _ ->
match c.TryGetValue(key) with
| (true, v) -> v
| _ -> defaultValue
This feels wrong - the code gets more and more nested with each map.
Does F# provide a way to "flatten" this code?

You could slightly change the semantics and run all TryGetValue calls up-front. Then you need just one flat pattern match, because you can pattern match on all the results at the same time and use the or pattern (written using |) to select the first one that succeeded:
match a.TryGetValue(key), b.TryGetValue(key), c.TryGetValue(key) with
| (true, v), _, _
| _, (true, v), _
| _, _, (true, v) -> v
| _ -> defaultValue
This flattens the pattern matching, but you might be doing unnecessary lookups (which probably is not such a big deal, but it's worth noting that this is a change of semantics).
Another option is to use an active pattern - you can define a parameterized active pattern that pattern matches on a dictionary, takes the key as an input parameter and performs the lookup:
let (|Lookup|_|) key (d:System.Collections.Generic.IDictionary<_, _>) =
match d.TryGetValue(key) with
| true, v -> Some v
| _ -> None
Now you can write pattern Lookup <key> <pat> which matches a dictionary when it contains a value matching pattern <pat> with the key <key>. Using this, you can rewrite your pattern matching as:
match a, b, c with
| Lookup key v, _, _
| _, Lookup key v, _
| _, _, Lookup key v -> v
| _ -> defaultValue
The way F# compiler handles this is that it will run the patterns one after another and match the first one that succeeds - so if the first one succeeds, only one lookup gets performed.

When control flow becomes a pain, it is sometimes helpful to transform the problem. Say you have this:
let a = [ (1, "a"); (2, "b") ] |> dict
let b = [ (42, "foo"); (7, "bar") ] |> dict
let key = 8
let defaultValue = "defaultValue"
Then the following shows the intent behind the computation: keep trying to get a value, if all fail, use the default.
[ a; b ]
|> Seq.tryPick (fun d -> let (s, v) = d.TryGetValue key in if s then Some v else None)
|> defaultArg <| defaultValue
The more dictionaries you have, the bigger the benefit.

You can also declare a TryGet function that applies a given function f to key only if the variable ok is false. If ok has become true we do nothing, we just return the given couple as input.
let ATryGetValue key =
if key>20 then (true,2) else (false,-2);
let BTryGetValue key =
if key>10 then (true,1) else (false,-1);
let CTryGetValue key =
if key>0 then (true,0) else (false,0);
let tryGet f (ok, key) =
if not ok then
match f key with
| (true, v) -> (true, v)
| _ -> (false, key)
else
(ok,key)
let res key =
tryGet CTryGetValue (tryGet BTryGetValue (tryGet ATryGetValue (false, key)))
printfn "%A" (res 40)

Related

Reversing Order of Linked List data type in f#

I have to reverse the order of a linked list that uses the following data type:
type IntList =
| Nil
| Cons of int * IntList
I have tried using a separate "append" method but I would like to know of a way to use a single function instead
let rec append num lst =
match lst with
| Nil -> Con (num,Nil)
| Cons (hd,tl) -> L (hd ,append num tl)
let rec reverse lst =
match lst with
| Nil -> Nil
| Cons (hd,tl) -> append hd (reverse tl)
You can have it in one function, by using accumator variable. When you go recursivly to the end of your list you just do nothing, but keep a variable that will store the result when you return from recursion back to the start of your list.
When you get to the end of your list you just return your acuumulator which was initally an empty list and then add all elements to it, while returning back.
Since you will have accumulator as your recursive function param, it's better to wrap it inside a function that will do nothing else but just supplying the initial value of accumulator.
type IntList =
| Nil
| Cons of int * IntList
let reverse lst =
let rec reverseHelper lst acc =
match lst with
| Nil -> acc
| Cons (hd,tl) -> reverseHelper tl (Cons (hd, acc))
reverseHelper lst Nil

How to use Map.TryFind?

When I run the code below I get an error. I am using Map.TryFind and its not working. In console, I get a red line under familyinc.TryFind(tract) and the error below.
let data =
seq { for (state,work) in statecsv do
let (family,income) = familyinc.TryFind(state)
let fam =
match fam with
| Some x -> x
| None -> "Not a Record"
let inc =
match inc with
| Some x -> x
| None -> "Not an income"
yield (state,work,inc,fam)
}
The ERROR:
error FS0001: This expression was expected to have type
''a * 'b'
but here has type
'(string * decimal) option'
Answer to the edited question: The problem is the same as in the previous one, you are pattern matching on a tuple while you are binding an option. You should do something like this instead:
// Bind the whole option
let result = familyinc.TryFind(state)
// Pattern match on it
match result with
| Some (family , income) -> yield (state,work,family,income)
| None -> yield (state,work,"Not a Record","Not an Income")
Of course you could also do match familyinc.TryFind(tract) with, there's no need to bind to variable here.
The issue is you are pattern matching on the result of Map.TryFind() as if it would return a tuple but it actually returns an option as it may fail to find they key you are looking for.
In all FP languages understanding option types and pattern matching is essential. In fact both of these features make FP a superior alternative to OO languages. Using option types you can avoid getting null exceptions, using pattern matching you can deconstruct values. In this case you can filter out non-existing keys, and convert the option result into normal values:
//create test dictionary
let map1 = [("a",1); ("b",2);("c",3)] |> Map.ofList
//list of keys, "d" doesn't exist in the dictionary/map
let keys = ["a";"b";"d"]
keys
|> List.map (fun x -> map1.[x])
//System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
keys
|> List.map (fun x -> map1.TryFind(x))
//You get back a string option list, with the last element missing as the key "d" doesn't exist
//val it : int option list = [Some 1; Some 2; None]
//Method A: filter out the none existing items
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.choose id //choose will get rid of the Nones and return the actual value, not the option. id is the identity function.
//Method B: replace the None with some default value, and also get rid of the option
//Let's say you replace each non existing value with 999
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.map (Option.defaultValue 999)
//val it : int list = [1; 2; 999]
//In general if necessary you can always pattern match
let myOption1 = Some "A"
let myOption2 = None
match myOption1 with
| Some x -> x //try matching whatever is in myOption1 and returns the x portion of Some x, in this case "A"
| None -> "No value"
//val it : string = "A"
match myOption2 with
| Some x -> x
| None -> "No value" //since the value of myOption2 is None, Some x won't match, None will match, and return "No value"
//val it : string = "No value"

F#: pattern matching on base types

I have a series of validation functions I want to put into an array to execute:
type result = {D: int; E: int; F: int; G: int}
type InvalidReason =
| AAA
| BBB
| CCC
| DDD
| EEE
type Validation =
| Valid
| Invalid of InvalidReason
let validators = [|AAA; BBB; CCC; DDD; EEE|]
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.contains(Validation.Invalid _)
The problem is that last line of code. I am getting an "Unexpected value _ in the expression." The following does work
|> Array.contains(Validation.Valid)
|> Array.contains(Validation.Invalid InvalidReason.AAA)
But I don't want to spell out each of the sub types for InvalidReasons. Is there some syntax I am overlooking?
The function Array.contains takes a value and checks if that value is in the array. What you're trying to do is to give it a whole bunch of values to check. Well, this won't work: the function only takes one. And it doesn't help that there is no syntax like that in F# :-)
You might use another function that takes multiple values, but a better way to accomplish what you want is to use a function that takes a predicate - Array.exists. Make yourself a predicate to check if a value is "invalid":
let isInvalid x = match x with
| Valid -> false
| Invalid _ -> true
And pass it to Array.exists:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists isInvalid
Or you could even put that function inline:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists ( fun x -> match x with
| Valid -> false
| Invalid _ -> true )
Or even shorter, using the function keyword:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists ( function | Valid -> false | Invalid _ -> true )
Or even shorter, getting rid of as much noise as possible:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists ( function Invalid _ -> true | _ -> false )

Avoiding the pyramid of doom with Computation Expressions?

I came across this question about the "pyramid of doom" in F#. The accepted answer there involves using Active Patterns, however my understanding is that it can also be solved using Computation Expressions.
How can I remove the "pyramid of doom" from this code using Computation Expressions?
match a.TryGetValue(key) with
| (true, v) -> v
| _ ->
match b.TryGetValue(key) with
| (true, v) -> v
| _ ->
match c.TryGetValue(key) with
| (true, v) -> v
| _ -> defaultValue
F# for fun and profit has an example for this specific case:
type OrElseBuilder() =
member this.ReturnFrom(x) = x
member this.Combine (a,b) =
match a with
| Some _ -> a // a succeeds -- use it
| None -> b // a fails -- use b instead
member this.Delay(f) = f()
let orElse = new OrElseBuilder()
But if you want to use it with IDictionary you need a lookup function that returns an option:
let tryGetValue key (d:System.Collections.Generic.IDictionary<_,_>) =
match d.TryGetValue key with
| true, v -> Some v
| false, _ -> None
Now here's a modified example of its usage from F# for fun and profit:
let map1 = [ ("1","One"); ("2","Two") ] |> dict
let map2 = [ ("A","Alice"); ("B","Bob") ] |> dict
let map3 = [ ("CA","California"); ("NY","New York") ] |> dict
let multiLookup key = orElse {
return! map1 |> tryGetValue key
return! map2 |> tryGetValue key
return! map3 |> tryGetValue key
}
multiLookup "A" // Some "Alice"
The pattern I like for "pyramid of doom" removal is this:
1) Create a lazy collection of inputs
2) Map them with a computation function
3) skip all the computations that yield unacceptable results
4) pick the first one that matches your criteria.
This approach, however, does not use Computation Expressions
open System.Collections
let a = dict [1, "hello1"]
let b = dict [2, "hello2"]
let c = dict [2, "hello3"]
let valueGetter (key:'TKey) (d:Generic.IDictionary<'TKey, 'TVal>) =
(
match d.TryGetValue(key) with
| (true, v) -> Some(v)
| _ -> None
)
let dicts = Seq.ofList [a; b; c] // step 1
let computation data key =
data
|> (Seq.map (valueGetter key)) // step 2
|> Seq.skipWhile(fun x -> x = None) // step 3
|> Seq.head // step 4
computation dicts 2
A short-circuiting expression can be achieved if we subvert the Bind method, where we are in a position to simply ignore the rest of the computation and replace it with the successful match. Also, we can cater for the bool*string signature of the standard dictionary lookup.
type OrElseBuilder() =
member __.Return x = x
member __.Bind(ma, f) =
match ma with
| true, v -> v
| false, _ -> f ()
let key = 2 in OrElseBuilder() {
do! dict[1, "1"].TryGetValue key
do! dict[2, "2"].TryGetValue key
do! dict[3, "3"].TryGetValue key
return "Nothing found" }
// val it : string = "2"

Different Expressions being generated for "roughly" the same code quotation

given the following type
type Foo = { foo: string; bar: int };;
and the following code quotation
<#fun v x -> { x with foo = v; bar = 99 } #>;;
this will result in
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, v, Value (99))))
Which is expected. Also the following code quotation
<#fun v x -> { x with bar = v;foo = "foo" } #>;;
yields the expected result.
val it : Quotations.Expr<(int -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, Value ("foo"), v)))
However this (changing the order and assigning the value to the second field)
<#fun v x -> { x with bar = 66;foo = v } #>;;
yields
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, Let (bar, Value (66), NewRecord (Foo, v, bar))))
a let. But there is no let in the code. Why is this?
Quotations only guarantee that they'll generate expressions with the correct behaviour, not any specific shape.
For example the quotation <## 1 = 2 || 2 = 3 ##> will generate an expression comprising of an if statement (i.e. if 1 = 2 then true else 2 = 3).
Normalising the resulting expressions is a pretty deep rabbit hole, but you can see some basic normalisers here: https://github.com/mavnn/Algebra.Boolean/blob/master/Algebra.Boolean/Transforms.fs
Specifically, check unbind at the end of the file.
let unbind quote =
let rec findLet q =
match q with
| Let (var, value, body) ->
findLet (replaceVar var.Name value body)
| ShapeLambda (v, e) ->
Expr.Lambda(v, findLet e)
| ShapeVar v ->
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map findLet)
and replaceVar name value q =
match q with
| Let (v, e, e') ->
if v.Name = name then
findLet (Expr.Let(v, e, e'))
else
Expr.Let(v, replaceVar name value e, replaceVar name value e')
| ShapeLambda (v, e) ->
Expr.Lambda(v, replaceVar name value e)
| ShapeVar v ->
if v.Name = name then
value
else
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map (replaceVar name value))
findLet quote
As to why these specific expressions are different? No idea, I'm afraid!
I believe what you are seeing here is a particular case of de-sugaring of the with syntax on records. I think what is happening here it is using the v to capture the value to ensure that the expressions are evaluated in the correct order of the fields. So in this case the let binding is introduce as the passed in parameter is the 2nd value being utilised.
This is from the F# language spec.
Primitive record constructions are an elaborated form in which the
fields appear in the same order as in the record type definition.
Record expressions themselves elaborate to a form that may introduce
local value definitions to ensure that expressions are evaluated in
the same order that the field definitions appear in the original
expression

Resources