6

在 Haskell 中,(liftM .liftM)、(liftM .liftM .liftM) 等有别名吗?

这样我就不必那么冗长了,例如:

(liftM . liftM) (+ 1) [Just 1,  Just 2]  = [Just 2, Just 3]
(liftM2 . liftM2) (+) [Just 1] [Just 2]  = [Just 3]
4

1 回答 1

7

base 中没有这样的东西,但在 Stack Overflow 上问了我一段时间以来最有趣的问题做得很好。

Functors 和 Applicative functors 在组合下是封闭的(对于 monad,当然不是一般情况,因此需要 monad 转换器),这就是为什么liftA2.liftA2在这里工作,liftM2通常只是liftA2,尤其是现在 Applicative 正在成为 Monad 的超类。

题外话:

您可以使用Data.Functor.Compose 包中的组合 newtype来组合 Applicative,但是您也可以通过其他方式从旧的 applicative 中创建新的 applicative - 我强烈推荐Gershom Bazerman 在 Comonad Reader forfolk中的文章“Abstracting with Applicatives”想要了解组合的 Applicative 结构与 monad 转换器堆栈相比有多漂亮 - 我现在一直在寻找让事情变得只是 Applicative 而不是 monadic 的东西,在那里我可以获得我需要的功能。通常我可以使用 Applicative 将所有输入内容组合成一个我想要输出的值,然后将它直接传递到我要使用的地方>>=

您的函数和运算符

当然,没有什么能阻止你定义自己的函数:

liftliftA2 :: (Applicative f, Applicative g) =>
              (a -> b -> c) -> f (g a) -> f (g b) -> f (g c)
liftliftA2 = liftA2.liftA2

但它并不比liftA2.liftA2.

不过,我喜欢你制作嵌套 Applicative 运算符的想法,但会切换到增加尖括号而不是重复内部运算符,因为与Control.Applicative<**>冲突,而且它更合乎逻辑。(<**>) = flip (<*>)

import Control.Applicative

(<<$>>) :: (Functor f, Functor g) => 
           (a -> b) -> f (g a) -> f (g b)
(<<$>>) = fmap.fmap

(<<*>>) :: (Functor m, Applicative m, Applicative n) =>
            m (n (a -> b)) -> m (n a) -> m (n b)
mnf <<*>> mna = (<*>) <$> mnf <*> mna

给予

ghci> (+) <<$>> [Just 5] <<*>> [Just 7,Just 10]
[Just 12,Just 15]

当然你可以继续:

(<<<$>>>) :: (Functor f, Functor g, Functor h) => 
             (a -> b) -> f (g (h a)) -> f (g (h b))
(<<<$>>>) = fmap.fmap.fmap

(<<<*>>>) :: (Functor l,Functor m, Applicative l, Applicative m, Applicative n) =>
             l (m (n (a -> b))) -> l (m (n a)) -> l (m (n b))
lmnf <<<*>>> lmna = (<*>) <<$>> lmnf <<*>> lmna

这可以让你做明显不可能的事情

ghci> subtract <<<$>>> Right [Just 5,Nothing,Just 10] <<<*>>> Right [Just 100,Just 20]
Right [Just 95,Just 15,Nothing,Nothing,Just 90,Just 10]

但是话又说回来,正如 Gershom Bazerman 的文章所展示的,您可能想要嵌套 Applicative,就像您想要嵌套 Monad 一样深。

于 2015-02-24T04:36:11.510 回答