为什么<$>只对一对中的第二个成员起作用?

Gre*_*g S 8 haskell functional-programming

快速浏览GHCi中的以下互动环节:

Prelude> import Control.Applicative
Prelude Control.Applicative> (+1) <$> [1,2]
[2,3]
Prelude Control.Applicative> (+1) <$> (1,2)
(1,3)

我认为<$>关于对的行为是有充分理由的,但到目前为止我找不到一个,所以:

为什么<$>(或fmap)定义为仅对一对的第二个成员起作用而不是对两个值起作用?

Nei*_*own 15

<$>(又名fmap)是Functor类的成员,如下所示:

class Functor f where
  fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

所以f必须是带有一个类型参数的参数化类型.列表是一种这样的类型,当以它们的前缀形式书写时[](与之[] a相同[a]).所以列表的实例是:

instance Functor [] where
  -- fmap :: (a -> b) -> [] a -> [] b 
  fmap = map
Run Code Online (Sandbox Code Playgroud)

对也可以用前缀形式编写:(,) 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)
Run Code Online (Sandbox Code Playgroud)

希望你能看到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)
Run Code Online (Sandbox Code Playgroud)

希望有助于解释一切!