<$>(又名fmap)是 Functor 类的成员,如下所示:
class Functor f where
fmap :: (a -> b) -> f a -> f b
因此,无论 f 是什么,都必须是具有一个类型参数的参数化类型。列表就是这样一种类型,当以前缀形式 [] 编写时([] a 与 [a] 相同)。所以列表的实例是:
instance Functor [] where
-- fmap :: (a -> b) -> [] a -> [] b
fmap = map
对也可以写成前缀形式:(,) a b 与 (a, b) 相同。因此,让我们考虑一下如果我们想要一个包含对的 Functor 实例该怎么办。我们不能声明instance Functor (,),因为对构造函数(,) 有两种类型——它们可以是不同的类型!我们可以做的是为(,) a 声明一个实例——这是一个只需要一个类型的类型:
instance Functor ( (,) a ) where
-- fmap :: (b -> c) -> (,) a b -> (,) a c
fmap f (x, y) = (x, f y)
希望您能看到 fmap 的定义是我们可以给出的唯一合理的定义。关于为什么函子实例对一对中的第二个项目进行操作的答案是,第二个项目的类型在列表中排在最后!我们不能轻易地声明一个对一对中的第一项进行操作的仿函数实例。顺便说一句,这可以推广到更大的元组,例如四元组(,,,) a b c d(又名(a, b, c, d))也可以在最后一项上有Functor 实例:
instance Functor ( (,,,) a b c) where
-- fmap :: (d -> e) -> (,,,) a b c d -> (,,,) a b c e
fmap f (p, q, r, s) = (p, q, r, f s)
希望这有助于解释这一切!