代码之家  ›  专栏  ›  技术社区  ›  Greg S

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

  •  8
  • Greg S  · 技术社区  · 14 年前

    快速浏览一下GHCi中的以下交互式会话:

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

    我想这是一个很好的理由 <$> 关于配对,但我还没找到,所以:

    为什么是 < (或 fmap

    3 回复  |  直到 7 年前
        1
  •  15
  •   Neil Brown    14 年前

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

    class Functor f where
      fmap :: (a -> b) -> f a -> f b
    

    [] [] a 与相同 [a] ). 所以列表的例子是:

    instance Functor [] where
      -- fmap :: (a -> b) -> [] a -> [] b 
      fmap = map
    

    (,) a b (a, b) . 让我们考虑一下,如果我们想要一个包含对的函子实例,我们该怎么办。我们 宣布 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)
    

    希望这有助于解释这一切!

        2
  •  4
  •   fuz    14 年前

    考虑一下 Functor 类型类:

    class Functor f where
      fmap :: (a -> b) -> f a -> f b
    

    * -> * . 因此,您只能为具有 *->* . 你能做的就是做这样的事情:

    instance Functor (,) where
      fmap :: (a -> b) -> (,) a -> (,) b
    

    这将适用于局部应用的元组,而且非常不方便。有人这样定义这个实例:

    instance Functor ((,) a) where
      fmap :: (b -> c) -> (,) a b -> (,) a c
      fmap f (x,y) = (x,f y)
    

    data T a = T a a
    
    instance Functor T where
      fmap f (T a b) = T (f a) (f b)
    

    那你想干什么就干什么。你看,因为那种 *->* 而不是 * -> * -> * ,一切都好。

        3
  •  2
  •   mb14    14 年前

    我想,元组不需要是同质的,我的意思是两种类型可以是不同的。如果你想要一个同构元组,你可以使用一个列表,然后fmap就可以了。

    你会怎么想 (+1) ("Hello", 2) 去上班?

    Prelude> import Control.Applicative
    Prelude Control.Applicative> (+1) <$> ("hello",2)
    ("hello",3)
    

    这只是工作,但没有特殊的行为时,这两种类型是相同的。 顺便说一下,我不知道为什么不使用第二个值而不是第一个值,但无论如何,您只能使用一个值。