import Control.Applicative
main = print $ fmap (*2) (1,2)
生成(1,4)
。我希望它能生成(2,4)
,但该函数仅应用于元组的第二个元素。
更新我基本上已经基本上直接解决了这个问题。我会在一分钟后发布自己的答案..
答案 0 :(得分:33)
让我回答这个问题:您期望哪个输出:
main = print $ fmap (*2) ("funny",2)
你可以拥有你想要的东西(使用data Pair a = Pair a a
左右),但由于(,)
在他们的第一个和第二个参数中可能有不同的类型,你就不在运气。
答案 1 :(得分:15)
Functor
实例实际上来自Control.Applicative
由Functor
导入的模块。
尝试编写我想要的实例,根据元组的定义,我可以看到它不起作用;实例只需要一个类型参数,而2元组有两个。
一个有效的(a,a)
实例至少必须在每个元素具有相同类型的元组 type T2 a = (a,a)
上,但你不能偷偷摸摸地做任何事情,比如定义实例:
data T2 a = T2 a a
因为实例类型不允许是同义词。
以上受限制的2元组同义词在逻辑上与类型相同:
instance Functor T2 where
fmap f (T2 x y) = T2 (f x) (f y)
哪个可以有一个Functor实例:
{{1}}
正如Gabriel在评论中所说,这对分支结构或并发性很有用。
答案 2 :(得分:15)
对,基本上是这样定义的:
data (,) a b = (,) a b
Functor
类看起来像这样:
class Functor f where
fmap :: (a -> b) -> f a -> f b
由于函数参数和结果的类型必须具有类*
(即它们代表值而不是可以应用于更多或更多异国情况的类型函数),我们必须a :: *
,{{ 1}},最重要的是,为了我们的目的,b :: *
。由于f :: * -> *
具有种类(,)
,因此必须将其应用于某种类型* -> * -> *
以获得适合*
的类型。因此
Functor
所以实际上没有办法写一个instance Functor ((,) x) where
-- fmap :: (a -> b) -> (x,a) -> (x,b)
实例做其他事情。
一个有用的类提供了更多使用对的方法,Functor
来自Bifunctor
。
Data.Bifunctor
这使您可以编写如下内容(来自class Bifunctor f where
bimap :: (a -> b) -> (c -> d) -> f a c -> f b d
bimap f g = first f . second g
first :: (a -> b) -> f a y -> f b y
first f = bimap f id
second :: (c -> d) -> f x c -> f x d
second g = bimap id g
):
Data.Bifunctor.Join
newtype Join p a =
Join { runJoin :: p a a }
instance Bifunctor p => Functor (Join p) where
fmap f = Join . bimap f f . runJoin
基本上与Join (,)
相同,其中
Pair
当然,您也可以使用data Pair a = Pair a a
实例直接使用对。