Recommend MonadFailDesugaring?
snoyberg opened this issue · 2 comments
I haven't used this extension myself previously, so my understanding may not be perfect. Consider this script:
#!/usr/bin/env stack
-- stack --resolver nightly-2018-04-15 script
{-# LANGUAGE NoImplicitPrelude #-}
-- {-# LANGUAGE MonadFailDesugaring #-}
{-# OPTIONS_GHC -Wall -Werror #-}
import RIO
main :: IO ()
main = runRIO () $ do
Just x <- return Nothing
return x
As is, it will crash at runtime with:
Main.hs: user error (Pattern match failure in do expression at /Users/michael/Desktop/Main.hs:10:3-8)
Note that even with -Wall -Werror
turned on, the compiler does nothing to prevent us from the partial pattern match Just x <- return Nothing
. By contrast, if we uncomment the {-# LANGUAGE MonadFailDesugaring #-}
line, we get a compiler time error due to a missing MonadFail
instance instead:
/Users/michael/Desktop/Main.hs:10:3: error:
• No instance for (Control.Monad.Fail.MonadFail (RIO ()))
arising from a do statement
with the failable pattern ‘Just x’
• In a stmt of a 'do' block: Just x <- return Nothing
In the second argument of ‘($)’, namely
‘do Just x <- return Nothing
return x’
In the expression:
runRIO ()
$ do Just x <- return Nothing
return x
|
10 | Just x <- return Nothing
It seems preferable to me to totally block partial pattern matches via this language extension and lack of MonadFail
instance for RIO
.
By the same token we should recommend -Wincomplete-uni-patterns
which is not enabled by -Wall
.
stack --resolver ghc-8.4.1 exec ghci
GHCi, version 8.4.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /Users/chris/.ghci
Prelude> :set -Wall
Prelude> let f = x where Just x = Nothing
Prelude> :set -fwarn-incomplete-uni-patterns
Prelude> let g = x where Just x = Nothing
<interactive>:5:17: warning: [-Wincomplete-uni-patterns]
Pattern match(es) are non-exhaustive
In a pattern binding: Patterns not matched: Nothing
Prelude>
+1 to both of these.
It's unfortunate that -Wincomplete-uni-patterns
doesn't catch the do-notation case, or I'd prefer just that by default. I think you're far more likely to have situations where you're stuck in Maybe
but legitimately know it's a Just
value in monadic code, due to the shape of other peoples' APIs; and the MonadFail error may not be clear to everyone, while the warning is nicely succinct. But it's better than nothing, and trivial to work around.