为什么2元组Functor实例仅将该函数应用于第二个元素?

时间:2012-11-18 17:22:21

标签: haskell tuples functor

import Control.Applicative

main = print $ fmap (*2) (1,2)

生成(1,4)。我希望它能生成(2,4),但该函数仅应用于元组的第二个元素。

更新我基本上已经基本上直接解决了这个问题。我会在一分钟后发布自己的答案..

3 个答案:

答案 0 :(得分:33)

让我回答这个问题:您期望哪个输出:

main = print $ fmap (*2) ("funny",2)

可以拥有你想要的东西(使用data Pair a = Pair a a左右),但由于(,)在他们的第一个和第二个参数中可能有不同的类型,你就不在运气。

答案 1 :(得分:15)

Functor实例实际上来自Control.ApplicativeFunctor导入的模块。

尝试编写我想要的实例,根据元组的定义,我可以看到它不起作用;实例只需要一个类型参数,而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 实例直接使用对。