使用 monad 转换器和身份 monad 派生基本 monad

Deriving a base monad using a monad transformer and the identity monad

我读到(例如 here and here)所有基本 monad (Mabye, Error, ...) 派生自它们对应的 monad 转换器 (MaybeT, ErrorT, ...) 使用 identity monad Identity。一个例子是:

type Maybe a = MaybeT Identity a

但这当然不会产生 Maybe a 的构造函数。 而在sourcesMaybeT定义为newtype MaybeT m a = MaybeT (m (Maybe a)).

我是不是漏掉了什么重要的东西? 如何使用相应的 monad 转换器和 identitiy monad 派生出一个 base monad 可以匹配的构造函数?

为了向后兼容,Maybe monad 未定义为 MaybeT Identity a,因为 Maybe 早在 MaybeT.

之前就是 GHC 的一部分

你是正确的,使用带有 Identity 的 monad 转换器不会产生可以匹配的类型构造函数。幸运的是,在使用 monad 转换器范例时,我从来不需要在 monad 构造函数上进行模式匹配。相反,您可以使用 do 表示法和 monad 操作(liftMrunReaderT 等)。

这里使用了不同的方法。

有时,基本 monad Foo 根据其转换器定义为 FooT Identity。例如,State 来自 transformer 包,正如 Daniel Wagner 指出的那样。

其他时候,基础 monad Foo 是独立定义的。在这些情况下,通常 FooFooT Indentity 是不同的类型,但是它们是 同构的 。这意味着您可以在两种类型之间进行转换而不会丢失任何信息。

我猜,由于Maybe在Haskell报告中被定义为Prelude类型,我们不能轻易将其重新定义为同构MaybeT Identity。实际上,由于通过针对 NothingJust _ 的模式匹配,Maybe a 中的 destruct/eliminate 值很常见,我们不能使用其他定义。如果我们 用户可定义的模式,我们可以使用 pattern Just x = Module.Just (Identity x),但我们没有这些(目前)。

相反,State 等其他单子不在 Prelude 中,也不在 Haskell 报告中。它们通常也不会被导入的人通过模式匹配破坏 Control.Monad.State。在这种情况下,改用 StateT Identity 变体感觉危害较小。