IO
在Haskell中比较棘手。线程,FFI,异步异常,懒惰,您都可以命名。
然后我们有MonadIO
,它允许在底部有IO
的Monadic堆栈分层。由于IO
动作可以执行任意操作,因此在这种不稳定的基础之上构建monadic堆栈有什么价值?
为什么存在?如果您确实需要执行任意副作用,为什么不构建自定义monad IO
?
答案 0 :(得分:2)
如今,使用the ReaderT design pattern是一种常见的方法。
您警惕将其他变压器置于IO之上,上面链接的博客文章解释了其中的某些原因。
但是,在将“通用应用程序配置”传递给所有功能时,ReaderT却提供了一些便利。
答案 1 :(得分:1)
在这种摇摇欲坠的顶部建立单子堆栈的价值是什么 基础?
IO
上方的变形金刚可以让您更方便地谈论重复动作的序列(因此various streaming libraries)。
他们还可以帮助进行externally allocated resources的簿记。
IO
的“野性”并不是将变压器堆叠在顶部的普遍反对意见,因为它们可以帮助您避免重复的代码并使基本逻辑更清晰。
相反,argument是IO
已经提供了一些内置功能来处理错误(exceptions)和可变引用(IORef
s,{{3} } ...),因此为已经存在的功能添加转换器可能会过大。
尤其是可变引用的一个论据是,“纯”所维持的状态意味着在弹出异常时消失,而这可能不是您想要的。您还可以从多个线程访问可变引用。
答案 2 :(得分:1)
MonadIO
实例的 类型的类型实现函数时, MonadIO
可能会很有用。
newtype FooMonad a
= FooMonad (StateT Int IO a)
deriving (Functor, Applicative, Monad)
doFoo :: FooMonad String
doFoo = FooMonad $ liftIO getLine
您可以使用MonadIO
和StateT Int
的{{1}}实例方便地定义“原始” IO
动作。其他使用模块的用户仅限于您选择导出的基元。