简体   繁体   中英

Why is the default catch-all not mandatory in a Haskell case statement?

Haskell has a reputation for being a safe language. One that generally speaking pushes more of the possible programming errors to compile-time errors, and less and run-time.

One example of this is the if expression. The else in the if is always mandatory. You need to cover off both possibilities. This is great because you have thought and covered off all possibilities of what will happen at runtime.

Now Haskell has a case expression. (This bears some similarity to switch statements in other OO and imperative languages - but Haskell adds a lot of richness in the type system).

describeList :: [a]
describeList xs = "The list is " ++ case cs of [] -> "empty."
                                               [x] -> "a singleton list."
                                               xs -> "a longer list."

But with the case expression, the default 'catch-all' is not mandatory.

To me this sounds like it would lead to runtime errors.

My question is: Why is the default catch-all not mandatory in a Haskell case statement?

Haskell is certainly safer than many other languages, especially mainstream ones, but it is far from 100% safe. Other unsafe features in Haskell include the ability to write infinite loops, like let x = x in x , or unsafePerformIO , or error , or undefined . I guess you could say it's just a tradeoff between convenience and safety.

In more complex code than your simple example, sometimes there's some cases that you know can't occur, and so you leave them out of your case expression, but Haskell's type system isn't strong enough for the compiler to be able know that those missing cases are impossible. (For example you might be computing some mathematical function that can only return the numbers 3 , 4 , or 5 , but that fact is due to some difficult theorem that you happen to know about and which the compiler is not aware of.)

For what it's worth, you can pass -fwarn-incomplete-patterns to the ghc compiler to get a warning whenever at compile time you're missing a branch in a case statement, if you like. That's included in the -W option which turns on several commonly desirable compiler warnings.

A catch-all is not always needed. If one handles all cases explicitly (the pattern matching is exhaustive ), a catch-all case would never be reached.

I can think of a serious drawback of a mandatory catch-all case: if one extends an ADT (algebraic data type), dependant code would still compile and the programmer is not reminded of that extra case they are supposed to handle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM