您对Show 的定义要求将show 应用于由Quad 数据构造函数包装的每个值,这会施加约束。如果你有一个像
这样的微不足道的实例,则不需要它
instance Show (Quad a) where
show (Quad a b c d) = "some Quad value"
因为这个定义并不关心 a 等人的类型:
> show (Quad 1 2 3 4)
"some Quad value"
> show (Quad (+1) (+2) (+3) (+4))
"some Quad value"
另一方面,fmap 具有(a -> b) -> f a -> f b 类型,因为fmap 本身对Quad 使用的类型没有任何限制;任何此类约束都由作为其第一个参数传递给 fmap 的任何函数施加:
> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :t fmap show
fmap show :: (Functor f, Show a) => f a -> f String
有时,Functor 的实例将需要一个约束。例如,考虑Data.Functor.Compose 中的Compose 类型:
data Compare f g = Compose { getCompose :: f (g a) }
忽略它的名字,它只需要两个类型为Type -> Type 的类型构造函数。但是,如果您想要 Compose 的 Functor 实例,那么这些类型构造函数也必须具有 Functor 实例,因为我们将在内部使用 fmap。
instance (Functor f, Functor g) => Functor (Compose f g) where
-- x :: f (g a)
fmap f (Compose x) = Compose (fmap (fmap f) x)
例如,fmap (+1) [1,2,3] == [2,3,4],但fmap (+1) [[1,2,3], [4,5,6]] 不会进行类型检查,因为(+1) 不能将列表作为参数。 Compose 让我们“深入”嵌套仿函数。
-- 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])