我查看了 this,试图了解几个 Transformer monad 是如何相互作用的,尤其是更好地理解
lift
和 stacking 与 monad。
对于here找到的RWST monad(我认为这是最好的文档),它是否是一个堆叠的monad,其中Reader,Writer,State每个都是一个monadic层(并且按照堆叠顺序)。或者说应该如何理解呢? 当我查看定义
runRWST :: r -> s -> m (a, s, w)
时,我将其理解为将读取器环境作为状态环境,并将任何 monad m
包装在 RWS
的返回值周围。这也意味着这个monad中只存在两层monad。即,外部单子 m
,以及包含多个单子的元组。
这也意味着您只能使用
lift
一次。将值从 reader 或 state monad 提升到外部 monad。
从这个意义上说,
get
和ask
只是应用两个内部单子之一的两个函数。对于最后一点,我仍然不确定为什么你需要一个 reader 和 state-monad,即使已经阅读了 this stackoverflow post。我猜 reader 仅对只读有意义,但如果不希望这样,可以在两个单独的 state-monad 周围使用转换器 monad 吗?
这些评论让我有理由思考并使以下内容更加明确......以下类型定义的内部单子和外部单子是什么?
RWST
本身是一个包裹着Either String
(内部单子)的单子(因此是外部单子)吗?
type MyRWST a = RWST
(String -> Either String MyType)
[Int]
(MyEnv, [String], [String])
(Either String)
a
monad transformer的内部monad始终是类型参数。您提供的类型不是变压器。
type MyRWST a = RWST
(String -> Either String MyType)
[Int]
(MyEnv, [String], [String])
(Either String)
a
此类型有种类
* -> *
,这是一种奇特的说法,它只需要一个类型参数。[1] 将其与像 MaybeT
这样的转换器进行比较。
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
MaybeT
采用两个类型参数,第一个本身采用一个参数,因此其类型为 (* -> *) -> * -> *
。如果加上更明确的括号,那就是 (* -> *) -> (* -> *)
。现在我们可以明白为什么它被称为transformer了。它需要一个单子(* -> *
类型)并将其转换为一个新的单子(也属于* -> *
类型)。
RWST
定义为
newtype RWST r w s m a = RWST { unRWST :: r -> s -> w -> m (a, s, w) }
现在需要大量类型参数,但是如果我们修复r
、
w
和
s
,我们就会得到一个变压器。也就是说,
RWST
本身并不是一个monad转换器,但对于任何
r
、
w
和
s
来说,
RWST r w s
是一个转换器。完整的 RWST
是
RWST :: * -> * -> * -> (* -> *) -> * -> *
虽然您可以认为RWST
具有三层(读取器、写入器和状态),但它实际上只有一层。
RWST r w s m
的“下一层”真的是
m
。因此,要直接回答有关
lift
的问题,
lift
的类型签名是
lift :: (MonadTrans t, Monad m) => m a -> t m a
当t ~ RWST r w s
时,我们得到
lift :: Monad m => m a -> RWST r w s m a
因此,一个lift
就让我们克服了整个
RWST r w s
的混乱。
[1] 事实上,MyRWST
甚至不是一个有效的类型。它的参数之一的类型为
Either String
,这不是
*
类型。您不能拥有
Either String
类型的值,因为
Either String
不是类型;它是一个类型构造函数。