icelake
icelake

Reputation: 13

haskell, monad, definition of bind, and weird pattern matching on an output value?

Below is some code coming from the answer to another stack overflow question. It's been several weeks i've started studying Haskell, and i had yet to encounter this particular syntax, and i can't find anywhere an explanation, not even a definition for it. So, the code:

data Pair a = P a a

instance Functor Pair where
  fmap f (P x y) = P (f x) (f y)

instance Monad Pair where
  return x = P x x
  P a b >>= f = P x y
     where P x _ = f a
           P _ y = f b

I spent the last half-hour trying to understand the meaning of it, or if something i already knew explained the definition of this bind (>>=) method. GHCI loaded it without fretting (well it demanded an Applicative instance but other than that), so it must be very much allowed, even if i have yet to understand the beginning of it.

What is the meaning of what looks like a definition by pattern-matching of an already defined data constructor? What are x and y, where do they come from?

Thanks to anyone who answers to that. And if anyone has a good idea for a good, specific title to this question -- given I really don't understand the very syntaxic meaning, I have trouble finding one.


@leftaroundabout gave me the information I needed, which was that that bit of code

P x y
  where P x _ = f a
        P _ y = f b

was a form of pattern-matching of the "value-unboxing" type, instead of the case of-like choice-oriented one. I was baffled by the presence of the _ pattern, and thus I didn't see the above two pattern-matchings as they were, that is, as the definitions of x then y, because it was done in a way I had never witnessed before.

I knew we could write something like that:

f :: foo -> (Int, Int)
...
i = let (a,b) = f x
    in a + b

but I didn't know we could use, in these cases of "value-unboxing" (here a and b for example, or x and y in the code that bugged me), the full extent of the possibilities in pattern-matching, that is, at least, definitions using _ to isolate the parts we don't want, the values we don't want to bind to any "label".

In short I didn't know that in the above example, this equation

P x _ = f a

was actually the definition of x through pattern-matching on the result of (f a), thus that it was strictly equivalent in effect to

x = g (f a)
  where g (P t _) = t

I was stuck at thinking it was the definition of the already-defined data constructor P.

Upvotes: 1

Views: 183

Answers (2)

leftaroundabout
leftaroundabout

Reputation: 120711

There is no “particular syntax” here, just a normal pattern matching. The code is equivalent to

pFst, pSnd :: Pair a -> a
pFst (Pair x _) = x
pSnd (Pair _ y) = y

instance Monad Pair where
  return x = P x x
  P a b >>= f = P x y
     where x = pFst $ f a
           y = pSnd $ f b

If you inline pFst and pSnd, you see that this leads straight to the original definition.

If you're not convinced, consider that (non-recursive) where bindings can be replaced with lambda abstractions:

  P a b >>= f = (\(Pair x _) (Pair _ y) -> P x y)
                  (f a)      (f b)

Evidently, that lambda could just as well be written as a named local function:

  P a b >>= f = pFstAndPSnd (f a) (f b)
   where pFstAndPSnd (Pair x _) (Pair _ y) = P x y

Perhaps it would have been less confusing if you had seen the code as it would look for ordinary tuples:

(>>=) :: (c,c) -> (c -> (d,d)) -> (d,d)
(a,b) >>= f = (x,y)
  where (x,_) = f a
        (_,y) = f b

This is obviously not redefining the (,) constructor in any way, just using it to pattern-match on tuple results of a function.


Well, ok, perhaps it's not that obvious, seeing as you can also do stuff like let 1+2=4 in 1+2, and get 4 as the result.

Upvotes: 4

Random Dev
Random Dev

Reputation: 52280

well P is indeed the constructor for the Pair so a and b will be the first and second element of this (a bit strange) pair (if you say x = P 1 2 an do x >>= f then here a = 1 and b = 2 - it's exactly pattern-matching

My guess is that you have trouble with the definition of the function. If it helps you could write it as:

(>>=) (P a b) f = P x y
    where ...

too

see: just as you can us the operator between arguments so can you define it there

Upvotes: 2

Related Questions