IO
在 Haskell 中很棘手。线程、FFI、异步异常、惰性等方面都需要考虑。
然后,我们有了 MonadIO
,它允许在底层使用 IO
来建立单调堆栈。由于 IO
动作可以执行任意操作,因此在这样不稳定的基础上构建单调堆栈的价值何在?
为什么要存在它?如果确实需要执行任意副作用,为什么不构建自定义单调堆栈 IO
呢?
MonadIO
可以在实现一个 非 MonadIO
实例类型的函数时非常有用。
newtype FooMonad a
= FooMonad (StateT Int IO a)
deriving (Functor, Applicative, Monad)
doFoo :: FooMonad String
doFoo = FooMonad $ liftIO getLine
StateT Int
和 IO
的 MonadIO
实例方便地定义“原始”FooMonad
操作。使用你的模块的其他人只能使用你选择导出的基本操作。现在使用ReaderT设计模式是一种常见的方法。
你对在IO之上放置其他转换器持谨慎态度是正确的,上述链接的博客文章解释了其中的一些原因。
然而,当涉及到向所有函数传递“公共应用程序配置”时,ReaderT提供了一个不错的小便利。
MonadIO
只是一个类型类,它将所有这样的“自定义 monad”分组在一起。恰好许多有用的 monad 可以表示为 monad transformer 堆栈。您确定您在此处的问题中表述得清楚吗? - AJFMonadIO
中”这句话的意思是什么?你是说我们无法知道IO
操作中发生了什么吗?使用单子变换器可以帮助我们理解,而不是阻碍。我仍然不清楚你的问题是什么。我建议提供一个具体的例子。 - AJF