Pis*_*tor 1 monads haskell functional-programming state-monad monad-transformers
我研究了这个,试图理解几个转换器单子如何相互作用,特别是更好地理解单子lift
并与单子堆叠。
对于这里找到的 RWST monad (我认为这是最好的文档),它是一个堆叠的 monad,其中 Reader、Writer、State 都是一个 Monadic 层(并且按照堆叠顺序)。或者说应该如何理解呢?当我查看定义时,runRWST :: r -> s -> m (a, s, w)
我将其理解为将读取器环境作为状态环境并将任何单子包装在 的m
返回值周围RWS
。这也意味着这个monad中只存在两层monad。即外部 monadm
和包含多个 monad 的元组。
这反过来也意味着您只能使用lift
一次。将读取器或状态单子中的值提升到外部单子中。
从这个意义上说get
, 和ask
只是应用两个内部单子之一的两个函数。对于最后一点,我仍然不确定我是否理解为什么即使阅读了这篇 stackoverflow 帖子,您仍然需要一个reader和一个state -monad 。我猜读者只对只读有意义,但如果不希望这样,可以在两个单独的状态单子周围使用变压器单子吗?
这些评论让我有理由思考并使以下内容更加明确......以下类型定义的内部单子和外部单子是什么?它本身是RWST
一个包裹着(因此是外部单子)Either String
(内部单子)的单子吗?
type MyRWST a = RWST
(String -> Either String MyType)
[Int]
(MyEnv, [String], [String])
(Either String)
a
Run Code Online (Sandbox Code Playgroud)
monad转换器的内部 monad始终是类型参数。您提供的类型不是变压器。
type MyRWST a = RWST
(String -> Either String MyType)
[Int]
(MyEnv, [String], [String])
(Either String)
a
Run Code Online (Sandbox Code Playgroud)
这是一个Monad
。将此与类似变压器进行比较MaybeT
。
Run Code Online (Sandbox Code Playgroud)newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
MaybeT
接受两个类型参数,第一个本身接受一个参数,所以它的种类是(* -> *) -> * -> *
。如果加上更明确的括号,那就是(* -> *) -> (* -> *)
. 现在我们可以明白为什么它被称为变压器了。它需要一个 monad(of kind * -> *
)并将其转换为一个新的 monad(也是 of kind * -> *
)。
RWST
定义为
Run Code Online (Sandbox Code Playgroud)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 :: * -> * -> * -> (* -> *) -> * -> *
Run Code Online (Sandbox Code Playgroud)
虽然您可以认为它RWST
具有三层(读取器、写入器和状态),但它实际上只有一层。的“下一层”RWST r w s m
确实是m
。因此,要直接回答您的问题lift
, 的类型签名lift
是
lift :: (MonadTrans t, Monad m) => m a -> t m a
Run Code Online (Sandbox Code Playgroud)
当 时t ~ RWST r w s
,我们得到
lift :: Monad m => m a -> RWST r w s m a
Run Code Online (Sandbox Code Playgroud)
因此,单曲lift
带领我们克服了整个 RWST r w s
混乱。