Pattern matching in do notation vs let
Asked Answered
K

1

10

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

Kristin answered 17/11, 2013 at 2:51 Comment(0)
N
14

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.

Nadean answered 17/11, 2013 at 3:21 Comment(5)
That is a very good point and answers the question as posted. That implies to me that there is some strictness difference that causes the error to be triggered in the do notation but not with the let notation in this case. Pattern matching in the IO monad forces the pattern pattern match while the let is lazy and allows it to evaluate later if required?Kristin
The let can definitely be lazier as with something like do { let Just x = Just (); return x } is equivalent to return (let Just x = Just () in x), while the same thing with binding pattern matching still needs to give the monad a chance to execute the bind.Nadean
This strange little difference in semantics is actually the whole reason why Monad has a fail function since it came into existence before MonadPlus did. There are also various proposals which have Monad pattern matching either desugar to let binding or only be valid for instances of MonadPlus.Nadean
I noticed that the fail function is deprecated now, so is this answer still accurate?Phytography
wow, I didn't understand any of those words lol. Maybe I need to learn some basic vocab to use haskell ha.Coreligionist

© 2022 - 2024 — McMap. All rights reserved.