Is it generally considered a bad practice to use non-exhaustive pattern machings in functional languages like Haskell or F#, which means that the cases specified don’t cover all possible input cases?
In particular, should I allow code to fail with a MatchFailureException etc. or should I always cover all cases and explicitly throw an error if necessary?
Example:
let head (x::xs) = x
Or
let head list =
match list with
| x::xs -> x
| _ -> failwith "Applying head to an empty list"
F# (unlike Haskell) gives a warning for the first code, since the []-case is not covered, but can I ignore it without breaking functional style conventions for the sake of succinctness? A MatchFailure does state the problem quite well after all …
If you complete your pattern-matchings with a constructor
[]and not the catch-all_, the compiler will have a chance to tell you to look again at the function with a warning the day someone adds a third constructor to lists.My colleagues and I, working on a large OCaml project (200,000+ lines), force ourselves to avoid partial pattern-matching warnings (even if that means writing
| ... -> assert falsefrom time to time) and to avoid so-called “fragile pattern-matchings” (pattern matchings written in such a way that the addition of a constructor may not be detected) too. We consider that the maintainability benefits.