我很确定这有一个简单的解决方案,但它使我无法找到一个直接的答案。
通常情况下,在应用liftA2
时假设二元函数已被提升一次,签名如下所示:
liftA2' :: (Applicative f1, Applicative f)
=> (f a -> f b -> f c) -> f1 (f a) -> f1 (f b) -> f1 (f c)
是否可以应用“反向”,例如liftA2
,例如:
inverseA2 :: (Applicative f, Applicative f1)
=> (f a -> f b -> f c) -> f (f1 a) -> f (f1 b) -> f (f1 c)
作为一个具体的例子,我想获得这个功能:
f :: ([a] -> [b] -> [c]) -> [Maybe a] -> [Maybe b] -> [Maybe c]
一种方法是使用“打包”每个参数[Maybe a] -> Maybe [a]
并“解包”Maybe [a] -> [Maybe a]
应用普通liftA2
的结果。我想避免这种情况,因为正如你所能想象的那样,打包具有破坏性(例如pack [Just 1, Nothing, Just 2] == Nothing
)。
更新,正如@ user2407038所指出的那样,为了让f
应用给定的函数,你需要一个与{em>一样的[Maybe a] -> [a]
行的函数丢失信息。因此,对于这两个特定的仿函数,没有明显的方法来满足所提出的额外要求。但对于任何其他具有可逆函数f
的两个仿函数f1
,forall a . f a -> f1 a
,接受的答案完全可以作为此问题的解决方案。
答案 0 :(得分:1)
我相信你可能已经想到了这一点,但我认为你不能用你所拥有的限制来做到这一点。如果你对你的约束更加自由,你会得到一些东西......
inverseA2 :: (Applicative f, Traversable f, Applicative f1, Traversable f1)
=> (f a -> f b -> f c) -> f (f1 a) -> f (f1 b) -> f (f1 c)
inverseA2 f x y = sequenceA (liftA2 f (sequenceA x) (sequenceA y))
我提出这个问题的唯一原因是,对于Maybe
和[]
的特定示例,这些约束 都已满足,因此这样做是可行的那种情况。但仍然没有解决。
您还可以尝试为Data.Distributive
编写自己的实例,为您提供distribute
,类似于sequenceA
......
编辑包含@ dfeuer的建议。