F# pattern matching on records with optional fields - f#

F#'s 'options' seem a nice way of using the type system to separate data that's known to be present from data which may or may not be present, and I like the way that the match expression enforces that all cases are considered:
match str with
| Some s -> functionTakingString(s)
| None -> "abc" // The compiler would helpfully complain if this line wasn't present
It's very useful that s (opposed to str) is a string rather than a string option.
However, when working with records that have optional fields...
type SomeRecord =
{
field1 : string
field2 : string option
}
...and those records are being filtered, a match expression feels unnecessary, because there's nothing sensible to do in the None case, but this...
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.filter (fun record -> record.field2.IsSome)
|> Seq.map (fun record -> functionTakingString field2) // Won't compile
... won't compile, because although records where field2 isn't populated have been filtered out, the type of field2 is still string option, not string.
I could define another record type, where field2 isn't optional, but that approach seems complicated, and may be unworkable with many optional fields.
I've defined an operator that raises an exception if an option is None...
let inline (|?!) (value : 'a option) (message : string) =
match value with
| Some x -> x
| None -> invalidOp message
...and have changed the previous code to this...
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.filter (fun record -> record.field2.IsSome)
|> Seq.map (fun record -> functionTakingString (record.field2 |?! "Should never happen")) // Now compiles
...but it doesn't seem ideal. I could use Unchecked.defaultof instead of raising an exception, but I'm not sure that's any better. The crux of it is that the None case isn't relevant after filtering.
Are there any better ways of handling this?
EDIT
The very interesting answers have brought record pattern matching to my attention, which I wasn't aware of, and Value, which I'd seen but misunderstood (I see that it throws a NullReferenceException if None). But I think my example may have been poor, as my more complex, real-life problem involves using more than one field from the record. I suspect I'm stuck with something like...
|> Seq.map (fun record -> functionTakingTwoStrings record.field1 record.field2.Value)
unless there's something else?

In this example, you could use:
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.choose (fun { field2 = v } -> v)
|> Seq.map functionTakingString
Seq.choose allows us to filter items based on optional results. Here we you pattern matching on records for more concise code.
I think the general idea is to manipulate option values using combinators, high-order functions until you would like to transform them into values of other types (e.g. using Seq.choose in this case). Using your |?! is discouraged because it is a partial operator (throwing exceptions in some cases). You can argue that it's safe to use in this particular case; but F# type system can't detect it and warn you about unsafe use in any case.
On a side note, I would recommend to take a look at Railway-Oriented Programming series at http://fsharpforfunandprofit.com/posts/recipe-part2/. The series show you type-safe and composable ways to handle errors where you can keep diagnostic information along.
UPDATE (upon your edit):
A revised version of your function is written as follows:
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.choose (fun { field1 = v1; field2 = v2 } ->
v2 |> Option.map (functionTakingString v1))
It demonstrates the general idea I mentioned where you manipulate option values using high-order functions (Option.map) and transform them at a final step (Seq.choose).

Since you have found the IsSome property, you might have seen the Value property as well.
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.filter (fun record -> record.field2.IsSome)
|> Seq.map (fun record -> functionTakingString record.field2.Value )
There's an alternative with pattern matching:
let functionTakingSequenceOfRecords' mySeq =
mySeq
|> Seq.choose (function
| { field2 = Some v } -> functionTakingString v |> Some
| _ -> None )

The problem as I interpreted is that you want to have the type system at all times reflecting the fact that those records in the collection actually contains a string in field2.
I mean, for sure you can use choose to filter out the records you don't care but still you will end up with a collection of records with an optional string and you know all of them would be Some string.
One alternative is to create a generic record like this:
type SomeRecord<'T> =
{
field1 : string
field2 : 'T
}
But then you can't use record expression to clone the record and change the generic type of the record at the same time. You will need to create the new record by hand, which will not be a major problem if the other fields are not so many and the structure is stable.
The other option is to wrap the record in a tuple with the desired value, here's an example:
let functionTakingSequenceOfRecords mySeq =
let getField2 record =
match record with
| {field2 = Some value} -> Some (value, record)
| _ -> None
mySeq
|> Seq.choose getField2
|> Seq.map (fun (f2, {field1 = f1}) -> functionTakingTwoStrings f1 f2)
So here you ignore the content of field2 and use instead the first value in the tuple.
Unless I misunderstood your problem and you don't care pattern matching again, or doing an incomplete matching with a warning or a #nowarn directive or using the .Value property of the option as shown in the other answers.

Related

How to split F# result type list into lists of inner type

I have a list/sequence as follows Result<DataEntry, exn> []. This list is populated by calling multiple API endpoints in parallel based on some user inputs.
I don't care if some of the calls fail as long as at least 1 succeeds. I then need to perform multiple operations on the success list.
My question is how to partition the Result list into exn [] and DataEntry [] lists. I tried the following:
// allData is Result<DataEntry, exn> []
let filterOutErrors (input: Result<DataEntry, exn>) =
match input with
| Ok v -> true
| _ -> false
let values, err = allData |> Array.partition filterOutErrors
This in principle meets the requirement since values contains all the success cases but understandably the compiler can't infer the types so both values and err contains Result<DataEntry, exn>.
Is there any way to split a list of result Result<Success, Err> such that you end up with separate lists of the inner type?
Is there any way to split a list of result Result<Success, Err> such that you end up with separate lists of the inner type?
Remember that Seq / List / Array are foldable, so you can use fold to convert a Seq / List / Array of 'Ts into any other type 'S. Here you want to go from []Result<DataEntry, exn> to, e.g., the tuple list<DataEntry> * list<exn>. We can define the following folder function, that takes an initial state s of type list<'a> * list<'b> and a Result Result<'a, 'b> and returns your tuple of lists list<'a> * list<'b>:
let listFolder s r =
match r with
| Ok data -> (data :: (fst s), snd s)
| Error err -> (fst s, err :: (snd s))
then you can fold over your array as follows:
let (values, err) = Seq.fold listFolder ([], []) allData
You can extract the good and the bad like this.
let values =
allData
|> Array.choose (fun r ->
match r with
| Result.Ok ok -> Some ok
| Result.Error _ -> None)
let err =
allData
|> Array.choose (fun r ->
match r with
| Result.Ok _ -> None
| Result.Error error -> Some error)
You seem confused about whether you have arrays or lists. The F# code you use, in the snippet and in your question text, all points to use of arrays, in spite of you several times mentioning lists.
It has recently been recommended that we use array instead of the [] symbol in types, since there are inconsistencies in the way F# uses the symbol [] to mean list in some places, and array in other places. There is also the symbol [||] for arrays, which may add more confusion.
So that would be recommending Result<DataEntry,exn> array in this case.
The answer from Víctor G. Adán is functional, but it's a downside that the API requires you to pass in two empty lists, exposing the internal implementation.
You could wrap this into a "starter" function, but then the code grows, requires nested functions or using modules and the intention is obscured.
The answer from Bent Tranberg, while more readable requires two passes of the data, and it seems inefficient to map into Option type just to be able to filter on it using .Choose.
I propose KISS'ing it with some good old mutation.
open System.Collections.Generic
let splitByOkAndErrors xs =
let oks = List<'T>()
let errors = List<'V>()
for x in xs do
match x with
| Ok v -> oks.Add v
| Error e -> errors.Add e
(oks |> seq, errors |> seq)
I know I know, mutation, yuck right? I believe you should not shy away from that even in F#, use the right tool for every situation: the mutation is kept local to the function, so it's still pure. The API is clean just taking in the list of Result to split, there is no concepts like folding, recursive calls, list cons pattern matching etc. to understand, and the function won't reverse the input list, you also have the option to return array or seq, that is, you are not confined to a linked list that can only be appended to in O(1) in the head - which in my experience seldom fits well into business case, win win win in my book.
I general, I hope to see F# grow into a more multi-paradigm programming language in the community's mind. It's nice to see these functional solutions, but I fear they scare some people away unnecessarily, as F# is already multi-paradigm!

F# Binary Search Tree

I am trying to implement BST in F#. Since I am starting my journey with F# I wanted to ask for help.
I have simple a test;
[<Fact>]
let ``Data is retained`` () =
let treeData = create [4]
treeData |> data |> should equal 4
treeData |> left |> should equal None
treeData |> right |> should equal None
Tree type which uses discriminated unions
type Tree<'T> =
| Leaf
| Node of value: 'T * left: Tree<'T> * right: Tree<'T>
a recursive function which inserts data nodes into the tree
let rec insert newValue (targetTree: Tree<'T>) =
match targetTree with
| Leaf -> Node(newValue, Leaf, Leaf)
| Node (value, left, right) when newValue < value ->
let left' = insert newValue left
Node(value, left', right)
| Node (value, left, right) when newValue > value ->
let right' = insert newValue right
Node(value, left, right')
| _ -> targetTree
now I have problems with create function. I have this:
let create items =
List.fold insert Leaf items
and resulting error:
FS0001 Type mismatch. Expecting a
''a -> Tree<'a> -> 'a' but given a
''a -> Tree<'a> -> Tree<'a>' The types ''a' and 'Tree<'a>' cannot be unified.
The List.fold documentation shows its type signature as:
List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State
Let's unpack that. The first argument is a function of type 'State -> 'T -> 'State. That means it takes a state and an argument of type T, and returns a new state. Here, the state is your Tree type: starting at a basic Leaf, you're building up the tree step by step. Second argument to List.fold is the initial state (a Leaf in this case), and third argument is the list of items of type T to fold over.
Your second and third arguments are correct, but your first argument doesn't line up with the signature that List.fold is expecting. List.fold wants something of type 'State -> 'T -> 'State, which in your case would be Tree<'a> -> 'a -> Tree<'a>. That is, a function that takes the tree as its first parameter and a single item as its second parameter. But your insert function takes the parameters the other way around (the item as the first parameter, and the tree as the second parameter).
I'll pause here to note that your insert function is correct according to the style rules of idiomatic F#, and you should not change the order of its parameters. When writing functions that deal with collections, you always want to take the collection as the last parameter so that you can write something like tree |> insert 5. So I strongly suggest you don't change the order of the arguments your insert function takes.
So if you shouldn't change the order of arguments of your insert function, yet they're in the wrong order to use with List.fold, what do you do? Simple: you create an anonymous function with the arguments flipped around, so that you can use insert with List.fold:
let create items =
List.fold (fun tree item -> insert item tree) Leaf items
Now we'll go one step further and generalize this. It's actually pretty common in F# programming to find that your two-parameter function has the parameters the right way around for most things, but the wrong way around for one particular use case. To solve that problem, sometimes it's useful to create a general-purpose function called flip:
let flip f = fun a b -> f b a
Then you could just write your create function like this:
let create items =
List.fold (flip insert) Leaf items
Sometimes the use of flip can make code more confusing rather than less confusing, so I don't recommend using it all the time. (This is also why there isn't a flip function in the F# standard library: because it's not always the best solution. And because it's trivial to write yourself, its lack in the standard library is not a big deal). But sometimes using flip makes code simpler, and I think this is one of those cases.
P.S. The flip function could also have been written like this:
let flip f a b = f b a
This definition is identical to the let flip f = fun a b -> f b a definition I used in the main example. Do you know why?

How to avoid multiple iterations as a pattern?

In functional languages (using F#), I am struggling to find a balance between the advantages of functional composition with single-responsibility and getting the performance of single iteration over sequences. Any code pattern suggestions / examples for achieving both?
I don't have a solid background in computational theory and I run into this general pattern over and over: Iterating over a collection and wanting to do side-effects while iterating to avoid further iterations over the same collection or its result set.
A typical example is a "reduce" or "filter" function: There are many times while filtering that I want to take an additional step based on the filter's result, but I'd like to avoid a second enumeration of the filtered results.
Let's take input validation as a simple problem statement:
Named input array
Piped to an "isValid" function filter
Side-effect: Log invalid input names
Pipe valid inputs to further execution
Problem Example
In F#, I might initially write:
inputs
// how to log invalid or other side-effects without messing up isValid??
|> Seq.filter isValid
|> execution
Solution Example #1
With an in-line side-effect, I need something like:
inputs
|> Seq.filter (fun (name,value) ->
let valid = isValid (name,value)
// side-effect
if not valid then
printfn "Invalid argument %s" name
valid
|> execution
Solution Example #2
I could use tuples to do a more pure separation of concerns, but requiring a second iteration:
let validationResults =
inputs
// initial iteration
|> Seq.filter (fun (name,value) ->
let valid = isValid (name,value)
(name,value,valid)
|> execution
// one example of a 2nd iteration...
validationResults
|> Seq.filter (fun (_,_,valid) -> not valid)
|> Seq.map (fun (name,_,_) -> printfn "Invalid argument %s" name)
|> ignore
// another example of a 2nd iteration...
for validationResult in validationResults do
if not valid then
printfn "Invalid argument %s" name
Update 2014-07-23 per Answer
I used this as the solution per the answer. The pattern was to use an aggregate function containing the conditional. There are probably even more elegantly concise ways to express this...
open System
let inputs = [("name","my name");("number","123456");("invalid","")]
let isValidValue (name,value) =
not (String.IsNullOrWhiteSpace(value))
let logInvalidArg (name,value) =
printfn "Invalid argument %s" name
let execution (name,value) =
printfn "Valid argument %s: %s" name value
let inputPipeline input =
match isValidValue input with
| true -> execution input
| false -> logInvalidArg input
inputs |> Seq.iter inputPipeline
Following up on my other answer regarding composition of logging and other side-effects in F#, in this example, you can write a higher-level function for logging, like this:
let log f (name, value) =
let valid = f (name, value)
if not valid then
printfn "Invalid argument %s" name
valid
It has this signature:
f:(string * 'a -> bool) -> name:string * value:'a -> bool
So you can now compose it with the 'real' isValid function like this:
inputs
|> Seq.filter (log isValid)
|> execution
Since the isValid function has the signature name:'a * value:int -> bool it fits the f argument for the log function, and you can partially apply the log function as above.
This doesn't address your concern of iterating the sequence only once (which, for an array, is very cheap anyway), but is, I think, easier to read and clearer:
let valid, invalid = Array.partition isValid inputs
for name, _ in invalid do printfn "Invalid argument %s" name
execution valid

Is there a more generic way of iterating,filtering, applying operations on collections in F#?

Let's take this code:
open System
open System.IO
let lines = seq {
use sr = new StreamReader(#"d:\a.h")
while not sr.EndOfStream do yield sr.ReadLine()
}
lines |> Seq.iter Console.WriteLine
Console.ReadLine()
Here I am reading all the lines in a seq, and to go over it, I am using Seq.iter. If I have a list I would be using List.iter, and if I have an array I would be using Array.iter. Isn't there a more generic traversal function I could use, instead of having to keep track of what kind of collection I have? For example, in Scala, I would just call a foreach and it would work regardless of the fact that I am using a List, an Array, or a Seq.
Am I doing it wrong?
You may or may not need to keep track of what type of collection you deal with, depending on your situation.
In case of simple iterating over items nothing may prevent you from using Seq.iter on lists or arrays in F#: it will work over arrays as well as over lists as both are also sequences, or IEnumerables from .NET standpoint. Using Array.iter over an array, or List.iter over a list would simply offer more effective implementations of traversal based on specific properties of each type of collection. As the signature of Seq.iter Seq.iter : ('T -> unit) -> seq<'T> -> unit shows you do not care about your type 'T after the traversal.
In other situations you may want to consider types of input and output arguments and use specialized functions, if you care about further composition. For example, if you need to filter a list and continue using result, then
List.filter : ('T -> bool) -> 'T list -> 'T list will preserve you the type of underlying collection intact, but Seq.filter : ('T -> bool) -> seq<'T> -> seq<'T> being applied to a list will return you a sequence, not a list anymore:
let alist = [1;2;3;4] |> List.filter (fun x -> x%2 = 0) // alist is still a list
let aseq = [1;2;3;4] |> Seq.filter (fun x -> x%2 = 0) // aseq is not a list anymore
Seq.iter works on lists and arrays just as well.
The type seq is actually an alias for the interface IEnumerable<'T>, which list and array both implement. So, as BLUEPIXY indicated, you can use Seq.* functions on arrays or lists.
A less functional-looking way would be the following:
for x in [1..10] do
printfn "%A" x
List and Array is treated as Seq.
let printAll seqData =
seqData |> Seq.iter (printfn "%A")
Console.ReadLine() |> ignore
printAll lines
printAll [1..10]
printAll [|1..10|]

Is List.partition guaranteed to preserve order?

I've noticed it seems to behave this way, but I don't want to rely on it if it's not intentional. Here's the code in question:
let bestValuesUnder max =
allValues
>> List.partition (fun value -> value < max)
>> function
| ([], bad) -> [List.min bad]
| (good, _) -> good // |> List.sortBy (fun value -> -value)
allValues is a function that returns an int list.
The spec does not say:
http://msdn.microsoft.com/en-us/library/ee353782(VS.100).aspx
but the current implementation in FSharp.Core does preserve order (it uses mutation under the hood to create the resulting lists in order, as it walks the original; this is efficient). I'll ask to see if we intend to promote this to the spec, as it seems like a useful guarantee.

Resources