假设我有两个功能
f :: Monad m => a -> m a
g :: a -> a
我想连续应用于某些元素,如下所示:
(return x) >>= f >>= g
这不起作用,因为 g 是纯的,所以我首先需要“人为地”将它变成 monadic。一种可能性是
(return x) >>= f >>= (return . g)
这对我来说不是很直观。另一种可能性是使用 Monad 是 Applicative:
(return g) <*> ((return x) >>= f)
但这不是很直观,因为函数和参数的顺序不同:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
处理这个问题的规范方法是什么?如果
(>>==) = (flip ((<*>) . pure))
可以写 ((pure x) >>= f) >>== g
,除了运算符优先级之外,这会很好。当然,一元代码中的纯函数很常见,所以肯定有一种标准的方法来处理它们吗?编辑:我最初没有这么说,但我在想这样一种情况,我有几个函数,有些是纯函数,有些是 monadic,我想以某种随机顺序应用它们。
最佳答案
我认为最直接的解决方案是来自 >=>
模块的 Kleisli 组合 Control.Monad
。
由于 >=>
和 (.)
都是右结合的并且 (.)
具有更高的优先级,因此可以编写以下内容:
-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
f :: Monad m => a -> m a
g :: a -> a
h :: Monad m => a -> m b
j :: b -> b
q :: Monad m => a -> m b
q = f >=> return . g >=> h >=> return . j
-- | |- Use (return .) to transform (a -> b) into (a -> m b)
-- |- Use Kleisli composition >=> to compose Kleisli arrows, i.e.
-- |- the functions going from values to monadic values, (a -> m b)
关于haskell - 单子(monad)中的纯映射,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59849190/