Reputation: 13
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
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
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