应用函子的逆提升
Inverse lifting on applicative functors
我很确定这有一个简单的解决方案,但它让我望而却步,我似乎找不到直接的答案。
通常,当应用liftA2
假设二进制函数已经被解除一次时,签名看起来像这样:
liftA2' :: (Applicative f1, Applicative f)
=> (f a -> f b -> f c) -> f1 (f a) -> f1 (f b) -> f1 (f c)
是否可以应用"inverse"的,例如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]
一种方法是诉诸 "pack" 每个参数 [Maybe a] -> Maybe [a]
和 "unpack" Maybe [a] -> [Maybe a]
应用正常 liftA2
的结果。我想避免这种情况,因为正如您可以想象的那样,打包具有破坏性(例如 pack [Just 1, Nothing, Just 2] == Nothing
)。
更新: 正如@user2407038 指出的那样,为了 f
应用给定的函数,你必须需要一个类似于 [Maybe a] -> [a]
的函数 会丢失信息。因此,对于这两个特定的函子,没有明显的方法来满足所提出的额外要求。但是对于任何其他两个具有可逆函数 forall a . f a -> f1 a
的函子 f
、f1
,接受的答案非常适合作为这个问题的解决方案。
我相信您可能已经明白了这一点,但我认为您无法在现有的限制条件下做到这一点。如果你对自己的限制更自由一点,你会得到一些东西......
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 的建议。
我很确定这有一个简单的解决方案,但它让我望而却步,我似乎找不到直接的答案。
通常,当应用liftA2
假设二进制函数已经被解除一次时,签名看起来像这样:
liftA2' :: (Applicative f1, Applicative f)
=> (f a -> f b -> f c) -> f1 (f a) -> f1 (f b) -> f1 (f c)
是否可以应用"inverse"的,例如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]
一种方法是诉诸 "pack" 每个参数 [Maybe a] -> Maybe [a]
和 "unpack" Maybe [a] -> [Maybe a]
应用正常 liftA2
的结果。我想避免这种情况,因为正如您可以想象的那样,打包具有破坏性(例如 pack [Just 1, Nothing, Just 2] == Nothing
)。
更新: 正如@user2407038 指出的那样,为了 f
应用给定的函数,你必须需要一个类似于 [Maybe a] -> [a]
的函数 会丢失信息。因此,对于这两个特定的函子,没有明显的方法来满足所提出的额外要求。但是对于任何其他两个具有可逆函数 forall a . f a -> f1 a
的函子 f
、f1
,接受的答案非常适合作为这个问题的解决方案。
我相信您可能已经明白了这一点,但我认为您无法在现有的限制条件下做到这一点。如果你对自己的限制更自由一点,你会得到一些东西......
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 的建议。