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

问题描述 投票:1回答:4

我有两个组成的应用函子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,但我对仅带有抽象的组合感兴趣。

haskell composition applicative
4个回答
4
投票

作为夏丽瑶said,使用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

3
投票

[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])

0
投票

另一种方法可能是使用ListT transformer。尽管在这种情况下它可以正常工作,但是由于某种原因,它是一个已贬值的转换器,标有红色的“已弃用:该转换器在大多数monad上无效”

ListT

0
投票

[两个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中的Compose newtype用于我们的优势:

Data.Functor.Compose

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

Data.Functor.Compose
© www.soinside.com 2019 - 2024. All rights reserved.