单子中的纯映射

Ste*_*zel 4 monads haskell

假设我有两个功能

f :: Monad m => a -> m a
g :: a -> a
Run Code Online (Sandbox Code Playgroud)

我想连续应用于某些元素,如下所示:

(return x) >>= f >>= g
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为 g 是纯的,所以我首先需要“人为地”将它变成 monadic。一种可能性是

(return x) >>= f >>= (return . g)
Run Code Online (Sandbox Code Playgroud)

这对我来说不是很直观。另一种可能性是使用 Monad 是 Applicative:

(return g) <*> ((return x) >>= f)
Run Code Online (Sandbox Code Playgroud)

但这不是很直观,因为函数和参数的顺序不同:

(>>=) :: Monad m => m a -> (a -> m b) -> m b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

处理这个问题的规范方法是什么?如果(>>==) = (flip ((<*>) . pure))可以写((pure x) >>= f) >>== g,除了运算符优先级之外,这很好。当然,一元代码中的纯函数很常见,所以肯定有处理它们的标准方法吗?

编辑:我最初没有这么说,但我在想这样一种情况,我有几个函数,有些是纯函数,有些是 monadic,我想以某种随机顺序应用它们。

Wil*_*sem 11

你在这里描述的是fmap :: Functor f => (a -> b) -> f a -> f b. 此外,由于pure x >>= f应该与 相同f x,因此我们可以将给定的表达式简化为:

fmap g (f x)
Run Code Online (Sandbox Code Playgroud)

或者我们可以使用中缀别名(<$>) :: Functor f => (a -> b) -> f a -> f b

g <$> f x
Run Code Online (Sandbox Code Playgroud)


lsm*_*mor 5

我认为最直接的解决方案是>=>来自Control.Monad模块的Kleisli 组合。

由于>=>(.)都是右结合并且(.)具有更高的优先级,因此您可以编写以下内容:

-- (>=>) :: 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)
Run Code Online (Sandbox Code Playgroud)

  • OP 已经简单地使用 `return 拒绝了。g` 为“不直观”,但我同意这是一种干净的方法。有些东西只有在通过重复使用“变得”直观之前才显得不直观:) (2认同)