【问题标题】:Deriving a base monad using a monad transformer and the identity monad使用单子转换器和身份单子派生基本单子
【发布时间】:2015-03-10 18:37:51
【问题描述】:

我读到(例如 herehere)所有基本单子 (Mabye, Error, ...) 派生自它们对应的单子变换器 (MaybeT, ErrorT, ...) 使用身份单子 Identity。一个例子是:

type Maybe a = MaybeT Identity a

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

我错过了什么重要的东西吗? 如何使用相应的 monad 转换器和 identitiy monad 导出一个基本 monad,从而产生一个具体的
可以匹配的构造函数?

【问题讨论】:

  • Maybebase 中定义,monad 转换器通常来自transformersmtl 之类的库。 Error monad 也来自一个库,还有 StateReaderWriter。在这种情况下,MaybeMaybeT 是奇怪的。
  • MaybeT Identity a 等价于Maybe a——它在Identity (Maybe a) 附近简化为一个新类型MaybeT——但实际上并不是一回事,部分原因是Maybe 被视为首先是数据结构,然后是 monad。
  • "例如type Maybe a = MaybeT Identity a。" No,但正确的例子是type State s = StateT s Identity

标签: haskell monads


【解决方案1】:

这里使用了不同的方法。

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

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

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

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

【讨论】:

  • 你在这里混淆了MaybeEither 吗? Maybe 既没有 Left 也没有 Right 构造函数。无论如何,丢失模式匹配可能不会是一个巨大的损失,因为像 maybefromMaybe 这样的实用函数已经是基础的一部分。
  • 我有时希望 StateT 是抽象的。有些人傻到在上面进行模式匹配,然后让其他人四处寻找结果元组的哪个组件是哪个。
【解决方案2】:

Maybe monad 未定义为 MaybeT Identity a 以实现向后兼容性,因为早在MaybeT 之前,Maybe 就是 GHC 的一部分。

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

【讨论】:

    猜你喜欢
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 2011-06-25
    • 2018-06-16
    相关资源
    最近更新 更多