commercialhaskell/rio

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> 
akhra commented

+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.