Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum of two values of discriminated union list F#

I have exercise to propose function that sum every value of the same type from discriminated union list like that:

type volume =
     | Litre of float
     | Galon of float
     | Bucket of float
     | Bushel of float

let list = [Litre(20.0);Litre(30.0);Galon(2.0);Bucket(5.0);Litre(5.0);Galon(3.0)];

Where output should looks like this:

[Litre(55.0);Galon(5.0);Bucket(5.0)]

I've come with part of the solution:

let rec sumSameTypes (list:volume list) =
    match list with
    | a::b::t -> if a.GetType() = b.GetType() then // and there is part where I don't know how to sum two of these elements
    | [] -> failwith "EMPTY"
like image 493
Jacek Krzyżanowski Avatar asked Mar 10 '23 00:03

Jacek Krzyżanowski


1 Answers

As this looks more like a learning question, I will try to give a few hints rather than a complete answer.

While GetType can (in this case) be used to check if two discriminated union values are of the same case, this is not particularly functional style. You will need to use pattern matching to check what case you've got, which also allows you to extract the numerical value:

match a with
| Litre(n) -> // Do something with 'n'
// Add all the other cases here

I think the first thing to consider is what do you want to get as the result - I suppose the easiest option would be to get four numbers representing the total number of litres, galons, buckets and bushels.

let rec sumSameTypes (list:volume list) : float * float * float * float =
    match list with
    | [] -> 
        // For empty list, we just have 0 of everything
        0.0, 0.0, 0.0, 0.0
    | x::xs ->
        // For non-empty list, process the rest recrsively
        // and pattern match on `x` to figure out which of 
        // the numbers you need to increment

This is quite basic approach, but I think it is the best way to get started. In general, you might use something like a map (from units to values), but then it would also make sense to use a type that looks more like:

type Unit = Litre | Galon | Bushel | Bucket
type Volume = { Amount : float; Unit : Unit }

This would make it much easier as you could use Map<Unit, float> as the result.

like image 71
Tomas Petricek Avatar answered Mar 19 '23 06:03

Tomas Petricek