我盯着算子,应用函子...我不知道如何到达我想要的地方,但我觉得遵循这些类型会让我更接近。
是否有一种简单的方法可以使map
- 类似于仅适用于2元组的第一个元素?从first
获取Control.Arrow
并使用Arrow (->)
,这很有效:
map . first :: (b -> c) -> [(b, d)] -> [(c, d)]
我唯一担心的是我还没有获得真正的箭头直觉,所以如果我坚持下去,我迟早会发现自己处于深水中。此外,这似乎是一个相当方便的案例,无法概括。
我可以通过使用仿函数,monad或其他任何东西获得相同的功能,同时了解我想要的内容吗?我正在玩弄
\f -> map (f `on` fst)
一样的想法,但无法到达那里。
答案 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