如何组合两个组合的应用函子?

How to combine two composed applicative functors?

我有两个组合的应用函子 Maybe [Integer] 并想将它们与 <$>/<*> 组合,但我坚持应用应用操作。以下不进行类型检查:

(<*>) (<*>) ((<$>) ((+) <$>) $ Just [1,2,3]) $ Just [4,5,6]

预期结果:

Just [5,6,7,6,7,8,7,8,9]

仿函数部分起作用,即作为第一个参数传递给 <*> 的中间值是 Just [Integer -> Integer]。我习惯了 S 表达式,所以我很难使用 Haskell 语法。我知道 Compose 但我只对没有抽象的组合感兴趣。

liftA2 可能比 (<*>).

更容易混淆
(+) :: Int -> Int -> Int
liftA2 (+) :: [Int] -> [Int] -> [Int]
liftA2 (liftA2 (+)) :: Maybe [Int] -> Maybe [Int] -> Maybe [Int]

liftA2 (liftA2 (+)) (Just [1,2,3]) (Just [4,5,6])

作为 Li-yao Xia ,使用 liftA2 可以减少很多混淆。

但是如果你还是看它在底层操作方面变成了什么,我们可以展开定义liftA2

liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x y = f <$> x <*> y

所以解变成

(liftA2 . liftA2) (+) (Just [1,2,3]) (Just [4,5,6])
= liftA2 (liftA2 (+)) (Just [1,2,3]) (Just [4,5,6])
= (\f x y -> f <$> x <*> y) ((\f x y -> f <$> x <*> y) (+)) (Just [1,2,3]) (Just [4,5,6])
= ((\f x y -> f <$> x <*> y) (+)) <$> Just [1,2,3] <*> Just [4,5,6]
= (\x y ->  (+) <$> x <*> y) <$> Just [1,2,3] <*> Just [4,5,6]

现在,这不像上面的示例那样采用无点风格,我真的认为将其转换为无点风格没有帮助,但这是 http://pointfree.io 的输出:

((<*>) . ((+) <$>)) <$> Just [1, 2, 3] <*> Just [4, 5, 6]

我们通过eta-expanding可以看出这是一样的:

(<*>) . ((+) <$>)
= \x y -> ((<*>) . ((+) <$>)) x y
= \x y -> ((<*>) $ ((+) <$>) x) y
= \x y -> ((<*>) ((+) <$> x)) y
= \x y -> (<*>) ((+) <$> x) y
= \x y -> ((+) <$> x) <*> y
= \x y -> (+) <$> x <*> y

另一种方法是使用 ListT transformer。虽然在这种情况下它工作得很好,但由于某种原因它是一个折旧的变压器,用红色标记 "Deprecated: This transformer is invalid on most monads".

import Control.Monad.Trans.List

doit :: (Int-> Int -> Int) -> Maybe [Int] -> Maybe [Int] -> Maybe [Int]
doit f mt1 mt2 = runListT $ f <$> (ListT mt1) <*> (ListT mt2)

λ> doit (+) (Just [1,2,3]) (Just [4,5,6])
Just [5,6,7,6,7,8,7,8,9]

两个 Applicative 的组合始终是一个 Applicative(与 Monad 的情况不同)。

我们可以利用 Data.Functor.Compose 中的 Compose newtype 来发挥我们的优势:

newtype Compose f g a = Compose { getCompose :: f (g a) }

它需要一些包装,但这种解决方案在适当的情况下可能会有用:

example :: Maybe [Int]
example =
  getCompose ((+) <$> Compose (Just [1,2,3]) <*> Compose (Just [4,5,6]))