checking if enough elements in a F# list - f#

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.

Related

Concatenating lists with recursion f#

I have an exercise that asks me to make a recursive function that uses # to create a list of [1;2;3..n]. Unfortunately I cannot get this method to work.
let lstInt: int list = []
let rec oneToN (n:int) : int list =
let addList = [n]
match n with
0 ->
lstInt
|_ ->
lstInt#addList
oneToN (n-1)
I have tried making my list mutable, but that doesn't seem to actually matter nor make much sense as you can still add and remove elements from lists in f# even though it is not mutable.
I have also tried removing space between # but that shouldn't matter either.
Edit: I should clarify, the issue is the lstInt#addList, which gives me the error:
"The result of this expression has type 'int list' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr"
That warning is not the issue, but it points you to the issue: you're creating a new list which is a concatenation of an empty list and [n], but then you're doing nothing with that new list. It's just dropped on the floor.
After that, you proceed to call oneToN (n-1) recursively and return its result. At the end of recursion, the very last call to oneToN will ultimately return an empty list, and that will be the return value of every previous iteration, since every iteration (except the last one) returns whatever the next iteration returns.
What you need to do is call oneToN (n-1), which will give you a list of numbers from 1 to n-1, and then append [n] to that list. And the result of that appending would be your return value: after all, if you take a list of numbers from 1 to n-1 and attach n to the end of it, you'll get a list of numbers from 1 to n.
let rec oneToN (n:int) : int list =
let addList = [n]
match n with
0 ->
lstInt
|_ ->
(oneToN (n-1)) # addList

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.

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

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!

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.

Comparing values in loop inside function

I want to make a function that takes an integer list as argument and compares every value and returns the largest value. In C# I would simply iterate through every value in the list, save the largest to a variable and return it, I'm hoping F# works similarly but the syntax is kinda iffy for me, here's what my code looks like. Also max2 is a function that compares 2 values and returns the largest.
let max_list list =
let a = 0 : int
match list with
| head :: tail -> (for i in list do a = max2 i a) a
| [] -> failwith "sry";;
You could use mutable variable and write the code using for loop, just like in C#. However, if you're doing this to learn F# and functional concepts, then it's good idea to use recursion.
In this case, recursive function is a bit longer, but it demonstrates the key concepts including pattern matching - so learning the tricks is something that will be useful when writing more complicated F# code.
The key idea is to write a function that takes the largest value found so far and calls itself recursively until it reaches the end of the list.
let max_list list =
// Inner recursive function that takes the largest value found so far
// and a list to be processed (if it is empty, it returns 'maxSoFar')
let rec loop maxSoFar list =
match list with
// If the head value is greater than what we found so far, use it as new greater
| head::tail when head > maxSoFar -> loop head tail
// If the head is smaller, use the previous maxSoFar value
| _::tail -> loop maxSoFar tail
// At the end, just return the largest value found so far
| [] -> maxSoFar
// Start with head as the greatest and tail as the rest to be processed
// (fails for empty list - but you could match here to give better error)
loop (List.head list) (List.tail list)
As a final note, this will be slow because it uses generic comparison (via an interface). You can make the function faster using let inline max_list list = (...). That way, the code will use native comparison instruction when used with primitive types like int (this is really a special case - the problem only really happens with generic comparison)
Also know that you can write a nice one-liner using reduce:
let max_list list = List.reduce (fun max x -> if x > max then x else max)
If your intention is to be able to find the maximum value of items in a list where the value of the items is found by the function max2 then this approach works:
let findMax list =
list
|> List.map (fun i -> i, max2 i)
|> List.maxBy snd
|> fst

Resources