通过阅读一些代码,我有时会遇到以Monad
为前缀的类型类,其中的示例包括MonadState
,MonadIO
,MonadReader
等。
这些目的究竟是什么?
以MonadState
为例,我知道
State
允许无状态状态StateT
允许使用其他monad,例如IO
到"结合" 两者的功能但是MonadState
允许究竟是什么?
我不需要另外一组类似命名的类型/类型类,有人可以解释一下吗?
答案 0 :(得分:7)
State
,StateT
以及其他类型来自transformers
,而MonadState
类型类和其他类型类似来自mtl
。请注意,前者是 types ,而后者是类型。
transformers
中的类型是Monad
和MonadTrans
的实例。你可以直接与他们合作,但有一些烦恼:
如果您有多个深层的monad堆栈,则必须通过大量调用lift
来填充代码,以便访问每个层的功能。
有时两种不同的类型提供相同的"界面"。例如,RWST
和ReaderT
都提供类似于读者的功能,例如ask
。在编写函数时,必须承诺执行其中一个函数是很烦人的,因为它会降低一般性。
来自Monad*
的{{1}}类型类可以缓解这些问题:
他们有"传递"消除对mtl
的许多调用的实例(或者更确切地说,自动处理它们)。例如,lift
是StateT
的一个实例,但MonadState
上的ReaderT
也是StateT
的一个实例,因此您可以使用MonadState
直接。
get
您可以在功能中添加import Control.Monad
import Control.Monad.Reader
import Control.Monad.State
-- put the environment in the state
bar :: ReaderT Int (State Int) ()
bar = ask >>= lift . put -- we use lift here
barMTL :: ReaderT Int (State Int) ()
-- This ONLY works if we have imported the
-- required instances from mtl.
-- The MonadState instance for ReaderT, in particular.
barMTL = ask >>= put -- the put is auto-lifted
约束,并对Monad*
"界面"而不是立即承诺monad的具体实现。通过这种方式,您的功能变得更加通用,并选择确切的"实现"被推迟到最后一刻。
Monad*
答案 1 :(得分:2)
MonadState
不是monad,而是Monad
的子类。 State
是monad(也是MonadState
)。 monad子类MonadState
用于使get
,put
等函数适用于任何具有gettable / settable“state”概念的monad。