Correct definition of a new type
I am wondering why the following is the correct implementation of the pair type. In particular, why Pair b a
not Pair a b
?
newtype Pair b a = Pair { getPair :: (a,b) }
To clarify, Pair a b
doesn't work for the following:
instance Functor (Pair c) where
fmap f (Pair (x,y)) = Pair (f x, y)
and I don't understand why.
In addition to a lot of great answers below, I found ghci helpful:
*Main> newtype Pair b a = Pair (a, b) deriving (Show, Eq)
*Main> :t Pair(True, "cat")
Pair(True, "cat") :: Pair [Char] Bool
*Main> newtype Pair a b = Pair (a, b) deriving (Show, Eq)
*Main> :t Pair(True, "cat")
Pair(True, "cat") :: Pair Bool [Char]
source to share
You are talking about the definition in LYAH :
newtype Pair b a = Pair { getPair :: (a,b) }
Pay attention to the paragraph that precedes it (emphasis mine):
It turns out that writing an instance for this is pretty heavy. With,
Maybe
we'll just say that a Functor instance can be, because since only type constructors that take exactly one parameter can be made a Functor instance. But it looks like there is no way to do something like this with(a,b)
so that the type parameter a turns out to be the one that changes as we usefmap
. To work around this, we can newtype our tuple so that the second type parameter represents the type of the first component in the tuple:
So, in this case, we want the type of the first element of the (main) pair to be the last type in the type constructor Pair
. Finally, we want to use fmap
for the first argument in LYAH:
-- b
-- |
-- v a isn't here…
instance Functor (Pair c) where
-- but here!
--fmap :: (a -> x) -> Pair c a -> Pair c x
fmap f (Pair (x,y)) = Pair (f x, y)
You can, of course, change the definition to newtype Pair b a = Pair { getPair :: (a,b) }
. But what happens in this case?
-- a
-- |
-- v b isn't here…
instance Functor (Pair c) where
-- but here! v---- c ----v--------------------------+
--fmap :: (b -> x) -> Pair c b -> Pair c x |
fmap f (Pair (x,y)) = Pair (f x, y) -- |
-- ^^^ uh-oh - that doesn't seem right-+
Remember your base type is now (a,b)
. However, your Functor
instance is a
now fixed, but you are trying to apply to it fmap
. This does not work. Instead, you should use fmap
for the second entry, which matches b
from the type constructor Pair a b
:
-- a
-- |
-- v b isn't here…
instance Functor (Pair c) where
-- but here!
--fmap :: (b -> x) -> Pair c b -> Pair c x
fmap f (Pair (x,y)) = Pair (x, f y)
-- ^^^ everything fine now.
But at this point we are back to the original instance (a,b)
.
source to share