7

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

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

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

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

我可以通过使用仿函数、单子或其他任何东西来获得相同的功能,同时达到我想要的核心吗?我在玩弄

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

- 类似的想法,但无法完全实现。

4

5 回答 5

10

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

所以例如

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

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

于 2012-05-30T14:55:49.040 回答
5

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

于 2012-05-30T15:03:18.823 回答
2

因此,您正在寻找 type 的功能(a -> b) -> (a,c) -> (b,c)。如果你能写就太好了

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

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

Hayoo 提出了调用该函数的包Data.Tuple.HTmapFst

如果不使用双函子(BiFunctor 实例(,)真的做你想要的,仅此而已)或箭头,就没有办法得到你想要的,至少我知道。

于 2012-05-30T20:08:26.677 回答
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")]
于 2012-05-30T21:15:38.127 回答
1

嗯,有BiFunctor包。

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

data Flip a b = Flip b a

instance Functor (Flip a) where
  fmap f (Flip x y) = Flip (f x) y
于 2012-05-30T15:13:06.783 回答