Haskell 应用函子的逆提升

Haskell 应用函子的逆提升,haskell,applicative,Haskell,Applicative,我很确定这有一个简单的解决办法,但我没有办法,我似乎找不到一个直接的答案 通常,当应用liftA2时,假设二进制函数已被解除一次,签名如下所示: liftA2' :: (Applicative f1, Applicative f) => (f a -> f b -> f c) -> f1 (f a) -> f1 (f b) -> f1 (f c) 是否可以应用例如liftA2的“逆”值,例如: inverseA2 :: (Ap

我很确定这有一个简单的解决办法,但我没有办法,我似乎找不到一个直接的答案

通常,当应用
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]
一种方法是对每个参数进行“打包”
[a]>[a]
和“解包”
或者[a]>[a]
应用正常的
liftA2
的结果。我希望避免这种情况,因为正如您所想象的那样,打包具有破坏性(例如,
pack[Just 1,Nothing,Just 2]==Nothing



更新:正如@user2407038所指出的,为了使
f
应用给定的函数,您必须需要一个与
[可能是a]->[a]
类似的函数,这会丢失信息。所以对于这两个特殊的函子,没有明显的方法来满足额外的要求。但是对于任何其他两个函子
f
f1
,它们对于所有a都具有可逆函数
。f a->f1 a
接受的答案非常适合作为这个问题的解决方案。

我相信你可能已经明白了这一点,但我认为你无法在现有的限制条件下做到这一点。如果你对自己的限制更开放一点,你会有所收获

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
[]
的特定示例,这些约束都得到了满足,因此在这种情况下,这样做是可能的。但仍然没有解决

您还可以尝试编写自己的实例,为您提供
distribute
,这类似于
sequenceA


编辑以包含@dfeuer的建议。

采用
f::[Int]->[Char]->[Int];f x y=[length x+length y]
。您对inverseA2 f.:[Maybe Int]->[Maybe Char]->[Maybe Int]有什么期望?那么
fxy=[length x+length y,head x]
呢?我不确定一般的定义是什么……为了使
f
应用给定的函数,它必须从
[可能a]
中生成
[a]
(自然没有办法从
[可能b]
中获得
[a]
,因为没有办法从
b
中获得
a
)因此,您需要一个函数
[可能是a]->[a]
-正如您所注意到的,这个函数必然会丢失信息。一般情况下也是如此-很少有函子
f1,f2
对所有a具有可逆函数
。f1 a->f2 a
@user2407038所以我没有找到一个简单的答案是有原因的,因为我看到的问题是错误的。感谢您指出可逆函数!我将对此进行更深入的研究。@chi为了用您的示例澄清这种情况,假设我得到的函数
f
已经定义为
f::[Int]->[Char]->[Int]
,我想将它应用到相应的结构
a=[Nothing,Just 1,Just 3]
b=[Just'a',Just'b']
。在这种情况下,第一个函数应该返回
inverseA2 f a b==[Just 5]
,而第二个函数应该是
inverseA2 f a b==[Just 5,Nothing]
。但是使用pack/unpack方法分别为第一个函数授予
[Nothing]
,为第二个函数授予
[Nothing]
。非常优雅
sequence
完美地描述了
pack
unpack
正在做的事情,感谢您指出这一点(现在我意识到,当我谈论转置时,我说的是胡言乱语,我会纠正这一点)!不幸的是,正如你所说,它正在实施我试图避免的情况。在上面的例子中,计算
inverseM2(\x y=[length x+length y])[Nothing,Just 1,Just 3][Just'a',Just'b']
将返回
[Nothing]
,而不是
[Just 5]
单子
显然是过分了(只需将
序列
替换为
序列a
)。此外,我还推测您可以使用
可遍历的
分布式的
的多种组合作为上下文。尽管您提供的资源非常宝贵,但我仍然遇到了输入参数“排序”的问题(即
[Maybe a]->Maybe[a]
)。对于这两个特殊的函子,我找不到这样的非破坏性变换,因为无法将
Nothing
描述为集合
a
中的值。所以我想我应该接受现状。