Search code examples
haskellpattern-matchingdo-notationthreepenny-gui

Pattern matching in do notation vs let


I recently encountered an error while using threepenny-gui and it was solved by changing the code from pattern match in the do notation with <- to pattern matching with the let notation.

Is there any reasons why I should expect a change in behavior when changing between these two forms of pattern matching?

Specifically the following code:

In the IO monad:

Just events <- Map.lookup elid <$> readMVar sElementEvents

was changed to:

mevents <- Map.lookup elid <$> readMVar sElementEvents
let Just events = mevents

Here is a link to the commit the fixed the problem for me: https://github.com/Davorak/threepenny-gui/commit/fbf6cbe25875fafdc64f7a111ddebf485b45143b

Additional platform details: os: 10.8.5 ghc: 7.6.3

edit: added the fact that this is happening the IO monad


Solution

  • Actually, yes, they produce different kinds of errors. Missing a pattern match in a let binding raises a pattern match error whenever that match is evaluated while missing a pattern match from (<-) just calls the Monad instance's fail function

    As a simple example, consider the Maybe monad where

    instance Monad Maybe where
      ...
      fail _ = Nothing
    
    test1 :: Maybe (Maybe ())
    test1 = do
      Just a <- return Nothing
      return a
    
    test2 :: Maybe (Maybe ())
    test2 = do
      ma <- return Nothing
      let Just a = ma
      return a
    

    If we call both of them, we get wildly different behavior

    > test1
    Nothing
    
    > test2
    Just *** Exception: PM.hs:23:7-17: 
    Irrefutable pattern failed for pattern Data.Maybe.Just a
    

    Generally irrefutable matching is a bad idea unless you're really certain it's impossible to get the missing patterns, but if you must do it in a Monad then sometimes irrefutable matching on a bind is better than in a let.