作为 Bifunctor 的类型不需要具有与值相同数量的a
值b
。例如,考虑
data TwoLists a b = TwoLists [a] [b]
这很容易实现bimap
,但othermap
确实是个问题,尤其是在其中一个列表为空的情况下。
othermap f (TwoLists [] (b:bs)) = TwoLists [] _
你能在这里做什么?您需要调用f
将所有的转换bs
为 type 的列表[d]
,但如果您手头有一个,您只能调用该函数a
。
也许更糟糕的是一种根本没有b
值的类型:
data TaggedFunction k a b = TaggedFunction a (k -> b)
instance Bifunctor (TaggedFunction k) where
bimap f g (TaggedFunction a b) = TaggedFunction (f a) (g . b)
你怎么能实现othermap
这种类型?您可以更新该功能,因为您a
手头有一个,并且b
在您需要时将拥有一个d
. 但是您无法将 a 替换为a
a c
,因为您无法使用 ab
来调用othermap
's 函数。
所以你不能把这个函数放在Bifunctor中。也许你会问,为什么不把它放在一个新的类中呢?我认为 leftroundabout 是正确的,因为该类太受限制而无用。只有当你的结构中有相同数量的s 和sothermap
时才能定义,即当你的结构是一些围绕 type 元组的函子时。例如,我们可以定义而不是 TwoListsa
b
f
(a, b)
newtype PairList a b = PairList [(a, b)]
这可以有一个othermap
定义。但它只是
othermap f (PairList vs) = PairList (fmap f vs)
同样,我们可以定义而不是 TaggedFunction
newtype MultiFunction k a b = MultiFunction (k -> (a, b))
但othermap
定义再次只是一个包装调用fmap
:
othermap f (MultiFunction g) = MultiFunction (fmap f g)
所以也许想象定义这个抽象的最好方法是,不是一个类型类函数,而是一个对捕获这个组合的类型进行操作的普通函数:
newtype TupleFunctor f a b = TupleFunctor (f (a, b))
othermap :: Functor f => ((a, b) -> (c, d))
-> TupleFunctor f a b -> TupleFunctor f c d
othermap f (TupleFunctor x) = TupleFunctor (fmap f x)