5

At HaskellWiki's Do notation considered harmful, section Useful applications, I found:

It shall be mentioned that the do sometimes takes the burden from you to write boring things.

E.g. in

getRight :: Either a b -> Maybe b
getRight y =
   do Right x <- y
      return x

a case on y is included, which calls fail if y is not a Right (i.e. Left), and thus returns Nothing in this case.

Calling fail (Nothing) on a pattern mismatch sounds interesting, so I wanted to try this out. However, the syntax looks wrong - we're not in the Either monad, so how can we extract anything from y?

Indeed, I tried and it gave me "Couldn't match type `Either a' with `Maybe'". So let's use the correct pattern matcher, let in here:

getRight y = do { let (Right x) = y; return x }

That gave me a syntax error "parse error on input `}'". Not that I understand why this doesn't work, but let's write it out in multiline notation:

getRight y = do
    let (Right x) = y
    return x

Ah, that seemed to work - parse at least. However:

*Main> getRight (Right 5)
Just 5
*Main> getRight (Left 5)
Just *** Exception: […]\test.hs:16:13-25: Irrefutable pattern failed for pattern (Data.Either.Right x)
-- `Nothing` was expected

What gives? So my questions are now:

  • What happened here? Why did my semicolon-brace line not work?
  • How to do it correctly (with do, everything else is trivial)?
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    The parse error on `getRight` is because in general, once you switch to explicit braces and semicolons, then all language constructs that are nested inside must use explicit braces and semicolons as well: `getRight y = do { let { Right x = y }; return x }` – kosmikus Feb 27 '14 at 08:30
  • @kosmikus: Hm, with that I'm getting a "*parse error on input \`='*" – Bergi Feb 27 '14 at 11:47
  • No idea. Works for me using ghc-7.4.2, ghc-7.6.3, and ghc-7.8.1-rc1 ... – kosmikus Feb 27 '14 at 12:01
  • 1
    @kosmikus: Uh, never mind. Total beginner mistake: I forgot the first `let` in ghci `let getRight x =` … – Bergi Feb 27 '14 at 17:18

1 Answers1

9

The example is probably meant to be

getRight :: Either a b -> Maybe b
getRight y =
   do Right x <- return y -- note: return = Just
      return x

where the pattern match failure calls fail = const Nothing. It is translated into:

getRight y = let ok (Right x) = do {return x}
                 ok _         = fail "pattern mismatch error"
             in return y >>= ok

FWIW most experienced folks seem to think fail as a Monad method was a wart. Check out MonadPlus for a maybe more principled approach to failure.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
jberryman
  • 16,334
  • 5
  • 42
  • 83
  • 2
    That page generally has some problems... for example, whole paragraphs being outdated with a footnote saying that they're outdated (why not just remove it then?). – Cubic Feb 26 '14 at 23:00
  • 1
    So only `<-` notation does call `fail` on pattern mismatch, `let` doesn't? Could you maybe show the code that the compiler generates when de-sugaring the `do`? – Bergi Feb 27 '14 at 11:44