【问题标题】:Can I map the first element of a pair without arrows?我可以映射一对没有箭头的第一个元素吗?
【发布时间】:2012-06-04 20:03:01
【问题描述】:

我正在关注函子、应用函子……我不确定如何到达我想要的地方,但我觉得遵循这些类型应该让我更接近。

有没有一种简单的方法来制作仅适用于 2 元组的第一个元素的 map-alike?从Control.Arrow 中提取first 并使用Arrow (->),这可以很好地解决问题:

map . first :: (b -> c) -> [(b, d)] -> [(c, d)]

我唯一担心的是我还没有对箭有真正的直觉,所以如果我继续这样做,我迟早会发现自己陷入困境。另外,这似乎是一个相当方便的案例,不能一概而论。

我能否通过使用仿函数、monad 或其他任何东西获得相同的功能,同时深入了解我想要的东西?我在玩弄

\f -> map (f `on` fst)

类似的想法,但无法实现。

【问题讨论】:

  • 如果使用你不理解的抽象让你感到不舒服,那么使用较少抽象的版本map (\(a, b) -> (f a, b))绝对没有错。
  • 感谢所有建议!这真的很有启发性。已接受您投票最多的答案。
  • 如果您对map . first 感到不舒服,请查看stackoverflow.com/questions/413930

标签: haskell arrows


【解决方案1】:

箭头有很好的组合器来操作元组。您几乎可以将它们视为缺失的元组函数!

例如

> :t \f -> map (f *** id)
  :: (b -> c) -> [(b, c')] -> [(c, c')]

是映射第一个组件的有用方法。

【讨论】:

  • 您还可以使用(来自 Control.Arrow)“map (first f)”将函数应用于一对的第一个元素,类似地使用“map (second f)”将其应用于第二个元素。
【解决方案2】:

另一个可以做这种事情的抽象是双函子。 Edward Kmett 有一个名为bifunctors 的包。 Data.Bifunctor 有一个类型类正好用于这个功能,它包括 2 元组的实例。

【讨论】:

    【解决方案3】:

    所以您正在寻找(a -> b) -> (a,c) -> (b,c) 类型的函数。如果你能写就太好了

    {-# LANGUAGE TupleSections #-}
    instance Functor (,c) where
        fmap f (x,c) = (f x, c)
    

    但不幸的是,元组部分仅适用于值级别。我不知道这是否有理论上的原因;我想它会破坏高阶类型统一。

    Hayoo 提出了包Data.Tuple.HT,其中的函数称为mapFst

    如果不使用双函子((,) 的 BiFunctor 实例确实可以满足您的需求,仅此而已)或箭头,就无法得到您想要的,至少我知道。

    【讨论】:

      【解决方案4】:

      我认为问题在于方法太多了——我想我会接受 Daniel Wagner 的建议——但这里有另一个供你娱乐:

      {-#LANGUAGE DeriveFunctor, MultiParamTypeClasses  #-}
      import Control.Newtype
      
      newtype P a b = P {p:: (b, a)} deriving (Show,Eq,Ord,Functor)
      instance Newtype (P a b) (b,a) where pack = P; unpack = p
      
       -- *Main> fmap even ("Hi",4)
       -- ("Hi",True)
       -- *Main> map (fmap even) [("Hi",4),("Bye",5)]
       -- [("Hi",True),("Bye",False)]
       -- *Main> under P (fmap even) (4,"Hi")
       -- (True,"Hi")
       -- *Main> map (under P (fmap even) ) [(4,"Hi"),(5,"Bye")]
       -- [(True,"Hi"),(False,"Bye")]
      

      【讨论】:

        【解决方案5】:

        嗯,有BiFunctor 包。

        或者您可以使用反向配对类型:

        data Flip a b = Flip b a
        
        instance Functor (Flip a) where
          fmap f (Flip x y) = Flip (f x) y
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多