通常情况下,extract
/ pure
来电时,return
可以通过monadic动作安全地使用unsafePerformIO (pure 42)
。例如。 newtype
不会影响世界。只要我只使用这些monadic操作,我就可以安全地使用纯片段。
我对一种概括性的概念感兴趣。我的第一个想法是使用Either
Left
和注入Right
表示纯值,{{1}}表示不可证明纯净值。编写monad实例非常简单。我甚至可以把它变成monad变压器。
我也知道免费的monad(变压器)结构。
专家对我应该走哪条路的意见是什么?
答案 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