7

双函子有一个带有这个签名的 map 函数:

bimap :: (a -> b) -> (c -> d) -> p a c -> p b d 

你也可以有这样的地图:

othermap :: ((a, c) -> (b, d)) -> p a c -> p b d

具有此函数的类型是双函子的严格子集(您始终可以定义bimapusing othermap,但反之则不行)。第二个签名有名字吗?

追问:这个中间函数呢?

halfothermap :: ((a, c) -> b) -> (c -> d) -> p a c -> p b d
4

2 回答 2

7

作为 Bifunctor 的类型不需要具有与值相同数量的ab。例如,考虑

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 替换为aa c,因为您无法使用 ab来调用othermap's 函数。

所以你不能把这个函数放在Bifunctor中。也许你会问,为什么不把它放在一个新的类中呢?我认为 leftroundabout 是正确的,因为该类太受限制而无用。只有当你的结构中有相同数量的s 和sothermap时才能定义,即当你的结构是一些围绕 type 元组的函子时。例如,我们可以定义而不是 TwoListsabf(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)
于 2021-12-28T04:19:14.373 回答
3

(扩展@glennsl 的评论...)

类型 p a c“包含”ac

但是类型函数(a, c) -> (b, d)需要类型被调用的值,类型值不一定同时具有。a cp a c

othermap @Either :: ((a, c) -> (b, d)) -> Either a c -> Either b d
othermap f (Left x) = ?
othermap f (Right y) = ?

无法othermap生成bor类型的值d,因为它在任何一种情况下都无法调用f

第一个参数的类型意味着一个与 同构的双函子(,),这对所有可能的双函子都不成立。othermap实际上,比具体bimap。(这里似乎有一个逆变关系,我不会试图做出精确的解释。)

于 2021-12-28T13:26:13.833 回答