为什么下面的代码为Show
的实例要求一个约束和类型参数,但是为使Quad
为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)
答案 0 :(得分:3)
您对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
的实例将需要一个约束。例如,考虑来自Compose
的{{1}}类型:
Data.Functor.Compose
忽略它的名称,只需要两个类型为data Compare f g = Compose { getCompose :: f (g a) }
的类型构造函数即可。但是,如果您想要Type -> Type
的{{1}}实例,则这些类型构造函数还必须具有Functor
实例,因为我们将在内部使用Compose
。
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)
答案 1 :(得分:0)
您正在对类型“ inside” Quad中的show
进行调用,因此它必须是Show
的实例,但是您不会对值inside中的Quad中的值fmap
进行调用您在fmap
上对Quad
的定义,因此没有理由要求它是Functor
的实例。