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]

      

+3


source to share


2 answers


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 use fmap

. 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)

.

+5


source


And that, and another newtype Pair a b

, and newtype Pair b a

are correct (for example, they check the type). In the latter case, the type of the second element is the first, which is counterintuitive, although it might be more appropriate in your use case.



0


source







All Articles