明确跟踪副作用monad中的纯粹动作?

时间:2014-11-29 12:10:37

标签: haskell monads

通常情况下,extract / pure来电时,return可以通过monadic动作安全地使用unsafePerformIO (pure 42)。例如。 newtype不会影响世界。只要我使用这些monadic操作,我就可以安全地使用纯片段。

我对一种概括性的概念感兴趣。我的第一个想法是使用Either Left和注入Right表示纯值,{{1}}表示不可证明纯净值。编写monad实例非常简单。我甚至可以把它变成monad变压器。 我也知道免费的monad(变压器)结构。

专家对我应该走哪条路的意见是什么?

2 个答案:

答案 0 :(得分:4)

对于Applicative,来自transformers包的Lift

Lift向已存在的Applicative添加明确纯粹的计算,并提供"优化" {1}}的实现,用于一个或两个参数明确纯粹的情况。

当基础<*>的{​​{1}}操作在某种程度上很昂贵时,这可能很有用。例如,考虑来自<*>的有用的Concurrently应用程序,它通过分叉线程并行运行两个Applicative操作。

执行类似

的内容
Control.Concurrent.Async

不会分叉任何线程。

对于IO实例,这样的事情可以起作用:

pure (+) <*> pure 5 <*> Other (Concurrently (return 5)) :: Lift Concurrently Int

我想知道为什么Monad还没有类似这个实例的东西。

答案 1 :(得分:2)

正如@danidiaz所写,对于应用仿函数,已有Lift。但是,monad(不像应用程序的编写器)不能编写,所以为此需要创建一个monad变换器:

import Control.Monad
import Control.Monad.Trans

data Impure m a = Pure a | Impure (m a)

instance (Monad m) => Monad (Impure m) where
    return = Pure
    (Pure x) >>= f = f x
    (Impure k) >>= f = Impure $ k >>= \x -> case f x of
                                                Pure y -> return y
                                                Impure l -> l

instance MonadTrans Impure where
    lift = Impure