我可以在没有箭头的情况下映射一对的第一个元素吗?

时间:2012-05-30 14:52:54

标签: haskell arrows

我盯着算子,应用函子...我不知道如何到达我想要的地方,但我觉得遵循这些类型会让我更接近。

是否有一种简单的方法可以使map - 类似于仅适用于2元组的第一个元素?从first获取Control.Arrow并使用Arrow (->),这很有效:

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

我唯一担心的是我还没有获得真正的箭头直觉,所以如果我坚持下去,我迟早会发现自己处于深水中。此外,这似乎是一个相当方便的案例,无法概括。

我可以通过使用仿函数,monad或其他任何东西获得相同的功能,同时了解我想要的内容吗?我正在玩弄

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

一样的想法,但无法到达那里。

5 个答案:

答案 0 :(得分:9)

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

所以,例如。

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

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

答案 1 :(得分:5)

另一种可以做这种事情的抽象是一个bifunctor。 Edward Kmett有一个名为bifunctors的包裹。 Data.Bifunctor具有完全符合此功能的类型类,它包含2元组的实例。

答案 2 :(得分:2)

所以你正在寻找类型为(a -> b) -> (a,c) -> (b,c)的函数。如果你可以写

那就太好了
{-# LANGUAGE TupleSections #-}
instance Functor (,c) where
    fmap f (x,c) = (f x, c)

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

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

如果没有bifunctors((,)的BiFunctor实例真的做你想要的东西而没有更多)或箭头,就没有办法得到你想要的东西,至少我知道。

答案 3 :(得分:2)

我认为问题在于有太多方法 - 我想我会选择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")]

答案 4 :(得分:1)

嗯,有BiFunctor个包。

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

data Flip a b = Flip b a

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