Determine if all elements of a list belong to the same DU case - f#

I have a discriminated union with 10-15 cases, all having data in the form of int<'a>:
type MyUnionType =
| Case1 of int<someUnit>
| Case2 of int<someUnit>
|
...
| CaseN of int<someOtherUnit>
I am new to functional programming and am struggling to write a function with the following signature:
mySum:MyUnionType option list -> MyUnionType option
The function should sum all the ints iff all the Some elements belong to the same DU case. For example:
mySum [Some (Case1 2<a>), Some (Case1 3<a>), None] = Some Case1 5<a>
mySum [Some (Case1 2<a>), Some (Case2 3<a>), None] = None
mySum [None] = None
I know about Option.map and List.choose and the likes that can help here, but I'm struggling with determining whether all elements belong to the same case.
Is there an elegant and FP-idiomatic way to write this function? (If it simplifies matters, you can assume the list is never empty.)
(Though I don't have a clear grasp on monoids/monads/morphisms yet, don't be afraid to use the words if relevant, though please stop a bit short of zygohistomorphic prepromorphisms).

First, the code I'm about to present you will be greatly simplified if you remove all the None cases from the list before summing it. So for the rest of my answer, I'm going to assume that you've run your list through a List.choose id step first to get rid of all the None values.
The simplest way to think about this is probably to break it down into a series of single steps. You start by taking the first item of the list to initialize your "sum so far" value. (If there was no first item after running the list through List.choose id, then the list was either empty or contained only Nones, so the sum in that case will be None). Now, if that was the only item of the list, then you've already found the sum of the entire list. Otherwise, you look at the first item of the rest of the list, and ask the following question:
Is that item the same DU case as the sum so far?
If the answer is yes, then you add its value to the sum so far, and keep going through the loop. If the answer is no, then you make the "sum so far" value a None value instead of Some (case). So really, the "is it the same as the sum so far" question is actually two questions:
Is the "sum so far" a real value? (I.e., not None)?
Is the item I'm looking at the same DU case as the sum so far?
If the answer to both of these questions is "yes", then you add up the two values to get a new "sum so far" value. If it's "no", then you just set the "sum so far" to None, and your eventual result will be None as well.
Translating that approach into code looks like this:
let addToSum sumSoFar nextItem =
match sumSoFar with
| None -> None // Short-circuit if we previously found a mismatch
| Some x ->
match x, nextItem with
| Case1 a, Case1 b -> Some (Case1 (a + b))
| Case2 a, Case2 b -> Some (Case2 (a + b))
// ...
| CaseN a, CaseN b -> Some (CaseN (a + b))
| _ -> None // Mismatch
Now you need a function to apply a "combining" operation like that to the whole list. (A "combining" operation is any operation that takes two items of the same type and produces a single item of that same type; addition is one such operation, but so is multiplication, and a bunch of other things). There are two basic "apply this combining operation to the whole list" functions in F#, reduce and fold. The difference is that reduce takes the first item of the list as the initial "sum so far" value, and cannot work on an empty list. Whereas fold requires you to supply the initial value of its "sum so far" accumulator, but it can work on an empty list (for an empty list, the result of fold will simply be the initial "sum so far" value that you provided). In your case, since you don't initially know the type that your "sum so far" value should hold, you have to use reduce. So I'd suggest something like this:
let sumMyList values =
values |> List.choose id |> List.reduce addToSum
Except that List.reduce can't handle an empty list, and if the list you have is entirely None cases, that would blow up. (Can you see why?) So I'll add one more step to it, to handle empty lists:
let reduceSafely filteredValues =
match filteredValues with
| [] -> None
| _ -> filteredValues |> List.reduce addToSum
let sumMyList values =
values |> List.choose id |> reduceSafely
That should get you what you're looking for. And hopefully it's also given you insight into the process of designing a functional solution to your problems.
P.S. I recommend the F# track at http://exercism.io/ if you want more practice in figuring out the functional approach to problem-solving. I learned a lot running through those exercises!

Related

checking if enough elements in a F# list

Right now I have a few instances like this:
let doIt someList =
if someList |> List.truncate 2 |> List.length >= 2 then
someList[0] + someList[1]
else
0
I need to grab the top 2 elements of a list quite often to see changes, but in some cases I don't have enough elements and I need to make sure there are at least 2.
The best way I've found so far is to truncate the list before getting its length, but this creates allocations for no reason.
Is there a better method?
I think I would suggest pattern matching in this case:
let doIt someList =
match someList with
| a :: b :: _ -> a + b
| _ -> 0
Here, a and b are the ints in the list, while _ represents a discarded of list int. This way you don't have to pull the first two elements out of the list with an index, as they are already available as a and b. The last case of the match catches any pattern that was not matched earlier, such as cases with zero, one or three-or-more elements.
This should be a cheap operation, as F# lists are implemented as a singly linked list. So [a;b;c;d] would be represented as a::(b::(c::(d::[]))). a and b are matched, while the rest (c::(d::[])) is left untouched (and is put in the _ slot). It does not need to create a new list to do so.

F# pattern matching with optional list of tuples

I'm trying to use pattern matching for an optional list of tuples but I could not write an exhaustive matching expression despite trying everything I can think of.
I'm struggling to understand why the F# compiler is insisting that my patterns in the following examples are not exhaustive.
module Mapper.PatternMatchingOddity
type A = A of string
type B = B of string
type ProblemType = ProblemType of (A * B) list option
//Incomplete pattern matches on this expression. Some ([_;_]) may indicate a case...
let matchProblem = function
|Some [(x:A,y:B)] -> []
|Some ([_,_]) -> [] //rider says this rule will never be matched
|None -> []
//same as before
let matchProblem1 = function
|Some [_,_] -> []
|Some [] -> []
//|Some _ -> []//this removes the warning but what is the case not covered by the previous two?
|None -> []
let matchProblem2 (input:ProblemType) =
match input with //same as before
|ProblemType (Some [(x:A,y:B)]) -> []
|ProblemType None -> []
How do I write the exhaustive matching and what am I missing above? Can you give an example for an input that would be accepted as a valid parameter to these functions and slip through the patterns?
Great question! I think many people that start out with F# grapple with how lists, options and tuples interact. Let me start by saying: the compiler is correct. The short answer is: you are only matching over singleton lists. Let me try to explain that a little deeper.
Your type is ('a * 'b) list option, essentially. In your case, 'a and 'b are themselves a single-case discriminated using of a string. Let's simplify this a bit and see what happens if we look at each part of your type in isolation (you may already know this, but it may help to put it in context):
First of all, your type is option. This has two values, None or Some 'a. To match over an option you can just do something like
match o with
| Some value -> value
| None -> failwith "nothing"`
Next, your type is a list. The items in a list are divided by semicolons ;. An empty list is [], a singleton list (one with a single item) is [x] and multiple items [x;y...]. To add something to the start of a list use ::. Lists are a special type of discriminated union and the syntax to match over them mimics the syntax of lists construction:
match myList with
| [] -> "empty"
| [x] -> printfn "one item: %A" x
| [x; y] -> printfn "two items: %A, %A" x y
| x::rest -> printfn "more items, first one: %A" x
Third, your list type is itself a tuple type. To deconstruct or match over a tuple type, you can use the comma ,, as with match (x, y) with 1, 2 -> "it's 1 and 2!" ....
Combine all this, we must match over an option (outer) then list (middle) then tuple. Something like Some [] for an empty list and None for the absence of a list and Some [a, b] for a singleton list and Some (a,b)::rest for a list with one or more items.
Now that we have the theory out of the way, let's see if we can tackle your code. First let's have a look at the warning messages:
Incomplete pattern matches on this expression. Some ([_;_]) may indicate a case...
This is correct, the item in your code is separated by , denoting the tuple, and the message says Some [something; something] (underscore means "anything"), which is a list of two items. But it wouldn't help you much to add it, because the list can still be longer than 2.
rider says this rule will never be matched
Rider is correct (which calls the FSC compiler services underneath). The rule above that line is Some [(x:A,y:B)] (the :A and :B are not needed here), which matches any Some singleton array with a tuple. Some [_,_] does the same, except that it doesn't catch the values in a variable.
this removes the warning but what is the case not covered by the previous two?
It removes the warning because Some _ means Some with anything, as _ means just that: it is a placeholder for anything. In this case, it matches the empty list, the 2-item list, the 3-item list the n-item list (the only one your match is the 1-item list in that example).
Can you give an example for an input that would be accepted as a valid parameter
Yes. Valid input that you were not matching is Some [] (empty list), Some [A "a", B "x"; A "2", B "2"] (list of two items) etc.
Let's take your first example. You had this:
let matchProblem = function
|Some [(x:A,y:B)] -> [] // matching a singleton list
|Some ([_,_]) -> [] // matches a singleton list (will never match, see before)
|None -> [] // matches None
Here's what you (probably) need:
let notAProblemAnymore = function
// first match all the 'Some' matches:
| Some [] -> "empty" // an empty list
| Some [x,y] -> "singleton" // a list with one item that is a tuple
| Some [_,a;_,b] -> "2-item list" // a list with two tuples, ignoring the first half of each tuple
| Some ((x,y)::rest) -> "multi-item list"
// a list with at least one item, and 'rest' as the
// remaining list, which can be empty (but won't,
// here it has at least three items because of the previous matches)
| None -> "Not a list at all" // matching 'None' for absence of a list
To sum it up: you were matching over a list that had only one item and the compiler complained that you missed lists of other lengths (empty lists and lists that have more than one item).
Usually it is not necessary to use option with a list, because the empty list already means the absence of data. So whenever you find yourself writing the type option list consider whether just list would suffice. It will make the matching easier.
You are struggling because your example is too “example”.
Let’s convert your example to a more meaningful one: check the input, so that
If it is none then print “nothing”, otherwise:
If it has zero element then print “empty”
If it has only one element then print “ony one element: ...”
If it has two elements then print “we have two elements: ...”
If it has three elements then print “there are three elements: ...”
If it has more than three elements then print “oh man, the first element is ..., the second element is ..., the third element is ..., and N elements more”
Now you can see that your code only covers the first 3 cases. So the F# compiler was correct.
To rewrite the code:
let matchProblem (ProblemType input) =
match input with
| None -> printfn "nothing"
| Some [] -> ...
| Some [(x, y)] -> ...
| Some [(x1, y1); (x2, y2)] -> ...
| Some [(x1, y1); (x2, y2); (x3, y3)] -> ...
| Some (x1, y1) :: (x2, y2) :: (x3, y3) :: rest -> // access rest.Length to print the number of more elements
Notice that I’m using pattern matching on the parameter ProblemType input so that I can extract the input in a convenient way. This makes the later patterns simpler.
Personally, when I learned F#, I didn’t understand many features/syntax until I used them in production code.

F# on List of Elements

I am trying to write a F# function that finds the biggest value. I am new to F# and am confused as to how to implement this with the correct type and recursion.
Any help would be greatly appreciated along with an explanation of how it works, I really need to understand how it works so I can attempt to create other F# functions. Thanks!
When creating recursive functions, start thinking about the corner cases. Your helper function takes a list and a "maximum so far". Corner cases: What if your list is empty? What if you only have a 1 element list, or focus on the first element? That directly translates into a match statement:
let rec helper (l, m) =
match l, m with
| [], m -> m
| (l1 :: rest), m ->
let max1 = if l1 > m then l1 else m
helper(rest, max1)
I'll leave the wrapper findMax open, but clearly you can solve that using the same thinking: What if you get an empty list? (scream!) What if you get a list with elements (the first element is your maximum so far, feed the rest of the list into your helper)
And of course you could put it all into one function. I've chosen this rather roundabout helper because your template code was shaped in that way.
The first thing to do is to start thinking recursively and/or mathematically. In most general vague terms, it should look like "The result of my function is..." - then try to actually put into words what the result should be.
Applying to your particular problem, I would phrase it like this:
when given a list of one element, the result of findMax is that element.
when given a list of more than one element, the result of findMax is the maximum of the lists's head and the maximum element of its tail.
This thinking can be translated into F# almost word for word:
let rec findMax list =
match list with
| [x] -> x
| head::tail -> max head (findMax tail)
where:
let max a b = if a > b then a else b
Note, however, that this function is incomplete: it doesn't specify what the result should be when given an empty list. I will leave this as an exercise for the reader.

F# how to handle nullable types

I try to do some graphs in F#. As an input I have CSV file that has some values nullable (e.g. nullable int). I try to show chart with following code :
[for row in data.Rows -> row.A.Value, row.B.Value] |> Chart.Point
Where both A and B are nullable integers. I received following error
System.InvalidOperationException: Nullable object must have a value.
How I should handle nullable types. Should I write some Option type to handle it or there is some other good way how to solve it.
If you are using F# 4.0, then there is a built-in function Option.ofNullable. If no, then you can use the implementation in the other answer.
You can also use the same code to define an active pattern:
let (|Present|_|) (n:System.Nullable<_>) =
if n.HasValue then Some(n.Value)
else None
... this can be used inside a match construct and so you can write:
[ for row in data.Rows do
match row.A, row.B wih
| Present a, Present b -> yield a,b
| _ -> () ] |> Chart.Point
Where you are going wrong is: you are calling the Value property on something that might be null.
When you call Value you are effectively saying "It's okay, I have rigorously changed this value and it's definitely not null so it's perfectly safe to treat it as if it were a non-nullable value." Of course, in this case, that condition isn't met, hence the runtime exception.
In F#, you don't want to be working with Nullable<'T> types, you want to be working with Option<'T>, this is much safer and the compiler can check more effectively that you're not making a mistake.
You can convert from Nullable<'T> to Option<'T> for the list using
[for row in data.Rows -> Option.ofNullable (row.A), Option.ofNullable(row.B)]
Of course then you have to decide how you want to handle the None cases but it's much easier to do that once you've made your design explicitly tell you that you've got a value that may or may not be something.
I don't know what behaviour you want but, as an example, perhaps you want to only chart the cases where both values are valid?
You could zip two option values:
module Option =
let zip a b =
match (a,b) with
|Some sa, Some sb -> Some(sa, sb)
|_ -> None
You can then map back to plotable numbers, extracting the None cases using List.choose.
[for row in data.Rows -> Option.ofNullable (row.A), Option.ofNullable (row.B)]
|> List.choose (fun (a,b) -> Option.zip a b)
|> Chart.Point
Map the Nullable type to Option type and filter them out (with .filter or .choose) or transform the None's to a special value for missing values (e.g. 0, -1, NaN) depending on your data to make them working in the charting tool.
module Option =
let fromNullable (n: _ Nullable) =
if n.HasValue
then Some n.Value
else None

What's the most "functional" way to select a subset from this array?

I'd like to get more comfortable with functional programming, and the first educational task I've set myself is converting a program that computes audio frequencies from C# to F#. The meat of the original application is a big "for" loop that selects a subset of the values in a large array; which values are taken depends on the last accepted value and a ranked list of the values seen since then. There are a few variables that persist between iterations to track progress toward determining the next value.
My first attempt at making this loop more "functional" involved a tail-recursive function whose arguments included the array, the result set so far, the ranked list of values recently seen, and a few other items that need to persist between executions. This seems clunky, and I don't feel like I've gained anything by turning everything that used to be a variable into a parameter on this recursive function.
How would a functional programming master approach this kind of task? Is this an exceptional situation in which a "pure" functional approach doesn't quite fit, and am I wrong for eschewing mutable variables just because I feel they reduce the "purity" of my function? Maybe they don't make it less pure since they only exist inside that function's scope. I don't have a feel for that yet.
Here's an attempted distillation of the code, with some "let" statements and the actual components of state removed ("temp" is the intermediate result array that needs to be processed):
let fif (_,_,_,_,fif) = fif
temp
|> Array.fold (fun (a, b, c, tentativeNextVals, acc) curVal ->
if (hasProperty curVal c) then
// do not consider current value
(a, b, c, Seq.empty, acc)
else
if (hasOtherProperty curVal b) then
// add current value to tentative list
(a, b, c, tentativeNextVals.Concat [curVal], acc)
else
// accept a new value
let newAcceptedVal = chooseNextVal (tentativeNextVals.Concat [curVal])
(newC, newB, newC, Seq.empty, acc.Concat [newAcceptedVal])
) (0,0,0,Seq.empty,Seq.empty)
|> fif
Something like this using fold?
let filter list =
List.fold (fun statevar element -> if condition statevar then statevar else element) initialvalue list
Try using Seq.skip and Seq.take:
let subset (min, max) seq =
seq
|> Seq.skip (min)
|> Seq.take (max - min)
This function will accept arrays but return a sequence, so you can convert it back using Array.ofSeq.
PS: If your goal is to keep your program functional, the most important rule is this: avoid mutability as much as you can. This means that you probably shouldn't be using arrays; use lists which are immutable. If you're using an array for it's fast random access, go for it; just be sure to never set indices.

Resources