Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

F# list pattern matching limitations or just bad writing?

Given some CreditScoreInput:

type CreditScoreInput = { id: string; score: string; years: int }

let input = [
    { id = "CUSTOMER001"; score = "Medium"; years = 1 }
    { id = "CUSTOMER001"; score = "Medium"; years = 1 }
    { id = "CUSTOMER002"; score = "Medium"; years = 10 }
    { id = "CUSTOMER003"; score = "Bad"; years = 0 }
    { id = "CUSTOMER003"; score = "Bad"; years = 0 }
    { id = "CUSTOMER003"; score = "Bad"; years = 0 }
    { id = "CUSTOMER004"; score = "Good"; years = 0 }
    { id = "CUSTOMER005"; score = "Good"; years = 10 }
]

My function validateDuplicates is out looking for duplicates:

let validate list =
    match list with
    | [] -> failwith "No customers supplied!"
    | _ -> list

let validateDuplicates (group:string * list<CreditScoreInput>) =
    match group with
    | (id, g) when g.Length = 1 -> printf $"No duplicates for {id} is OK.\n"
    | (id, [input1; input2]) -> printf $"Two duplicates for {id} is OK.\n"
    | (id, g) when g.Length > 2 -> printf $"More than two duplicates for {id} is NOT OK.\n"

    true

input
|> validate
|> List.groupBy (fun i -> i.id)
|> List.forall (fun i -> i |> validateDuplicates)
|> ignore

Inside of validateDuplicates I notice a little squiggly under group, leading to the warning:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Incomplete pattern matches on this expression. For example, the value (_,[_;_;_]) may indicate a case not covered by the pattern(s). However, a pattern rule with a when clause might successfully match this value.

Is there a way I can play nice with the compiler to avoid this warning?

>Solution :

Just get rid of the last when clause, because you know it will always be true:

    match group with
    | (id, g) when g.Length = 1 -> printf $"No duplicates for {id} is OK.\n"
    | (id, [input1; input2]) -> printf $"Two duplicates for {id} is OK.\n"
    | (id, g) -> printf $"More than two duplicates for {id} is NOT OK.\n"

Proof:

  • g.Length can never be negative or 0
  • If g.Length is 1 then it will match the first case
  • If g.Length is 2 then it will match the second case
  • Therefore, g.Length will always be > 2 if control reaches the third case.

Note: There are some other issues with your code that I’ve ignored, since they’re not directly relevant to your question.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading