Reputation: 1137
Why does the code below require a constraint and the type parameter for an instance of Show
but are they need required for making Quad
an instance of Functor
?
data Quad a = Quad a a a a
instance (Show a) => Show (Quad a) where
show (Quad a b c d) = show a ++ " " ++ show b ++ "\n" ++
show c ++ " " ++ show d
instance Functor Quad where
fmap f (Quad a b c d) = Quad (f a) (f b) (f c) (f d)
Upvotes: 0
Views: 86
Reputation: 530793
Your definition of Show
requires show
be applied to each value wrapped by the Quad
data constructor, which imposes the constraint. It would not be needed if you had a trivial instance like
instance Show (Quad a) where
show (Quad a b c d) = "some Quad value"
because this definition doesn't care about the type of a
et al.:
> show (Quad 1 2 3 4)
"some Quad value"
> show (Quad (+1) (+2) (+3) (+4))
"some Quad value"
fmap
, on the other hand, has type (a -> b) -> f a -> f b
, because fmap
itself places no constraint on the type used by Quad
; any such constraints are imposed by whatever function is passed to fmap
as its first argument:
> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :t fmap show
fmap show :: (Functor f, Show a) => f a -> f String
Sometimes, an instance for Functor
will require a constraint. For example, consider the Compose
type from Data.Functor.Compose
:
data Compare f g = Compose { getCompose :: f (g a) }
Ignoring its name, all it requires is two type constructors with kind Type -> Type
. But, if you want a Functor
instance for Compose
, then those type constructors must also have Functor
instances, because we'll use fmap
internally.
instance (Functor f, Functor g) => Functor (Compose f g) where
-- x :: f (g a)
fmap f (Compose x) = Compose (fmap (fmap f) x)
For example, fmap (+1) [1,2,3] == [2,3,4]
, but fmap (+1) [[1,2,3], [4,5,6]]
wouldn't typecheck, because (+1)
can't take a list as an argument. Compose
lets us "dig into" the nested functor.
-- Compose [[1,2,3],[4,5,6]] :: Num a => Compose [] [] a
> fmap (+1) (Compose [[1,2,3], [4,5,6]])
Compose [[2,3,4],[5,6,7]]
-- Compose [Just 3, Just 4, Nothing] :: Num a => Compose [] Maybe a
> fmap (+1) (Compose [Just 3, Just 4, Nothing])
Compose [Just 4,Just 5,Nothing]
-- Compose Nothing :: Compose Maybe g a
> fmap (+1) (Compose Nothing)
Nothing
-- Compose (Just [1,2,3]) :: Num a => Compose Maybe [] a
> fmap (+1) (Compose (Just [1,2,3]))
Compose (Just [2,3,4])
Upvotes: 3
Reputation: 110
You are calling show
on the type "inside" Quad so it needs to be an instance of Show
but you aren't calling fmap
on the values "inside" Quad in your definition of fmap
on Quad
so there is no reason to require it is an instance of Functor
.
Upvotes: 0