Opened 2 years ago

Closed 2 years ago

#13517 closed bug (invalid)

No warnings produced, yet the pattern matching fails at runtime.

Reported by: timotej.tomandl Owned by:
Priority: normal Milestone:
Component: Compiler Version: 8.0.1
Keywords: PatternMatchWarnings Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

The code below should produce a warning about a non-exhaustive pattern in the failure, yet it compiles alright.

{-# OPTIONS_GHC -Wall -Werror #-}

action :: (Monad m)=>t->m (Maybe a)
action _=return Nothing

failure :: (Monad m)=>Int->(m Int)
failure x=do
    Just y<-action x
    return y

main :: IO()
main=do
    y<-failure 1
    putStrLn $ (show y)

The same should be the case if we replace the definition of failure with

failure :: (Monad m)=>Int->(m Int)
failure x=(action x)>>=(\(Just y)->return y)

yet once again no warnings are produced.

Change History (1)

comment:1 Changed 2 years ago by RyanGlScott

Resolution: invalid
Status: newclosed

Both of these examples are working as expected, for some definition of "expected".

One thing to note here: the versions of failure you've given are not quite semantically equivalent. I'll go over the second example first, since it's easier to explain:

failure :: (Monad m)=>Int->(m Int)
failure x=(action x)>>=(\(Just y)->return y)

You're right—this is partial, and moreover, -Wall doesn't warn about this. There is a flag that warns about this, however: -Wincomplete-uni-patterns. As for why it's not a part of -Wall, to quote the users' guide:

This option isn’t enabled by default because it can be a bit noisy, and it doesn’t always indicate a bug in the program. However, it’s generally considered good practice to cover all the cases in your functions, and it is switched on by -W.

So you can enable -Wincomplete-uni-patterns or -W if you want a warning for this.

Now, back to the first example:

failure :: (Monad m)=>Int->(m Int)
failure x=do
    Just y<-action x
    return y

Pattern matching in do-notation is handled a bit differently than in other contexts. The Haskell Report has a nice section on this. Effectively, that implementation of failure gets desugared down to this:

failure :: Monad m => Int -> m Int
failure x = let ok (Just y) = return y
                ok _        = fail "Pattern match failure in do expression..."
            in action x >>= ok

Which is actually total! But it does rely on the fail method of Monad, which some find a bit unsavory. Relatedly, fail will eventually be split out of Monad and into a separate MonadFail class at some point in the future.

It's important to note that not all implementations of fail throw exceptions. For instance, here are some demonstrations of failure used on particular Monads:

λ> failure 1 :: IO Int
*** Exception: user error (Pattern match failure in do expression at Bug.hs:7:5-10)
λ> failure 1 :: Maybe Int
Nothing
λ> failure 1 :: [Int]
[]
Note: See TracTickets for help on using tickets.