首页 文章

没有monad变换器的monad的明确示例是什么? [重复]

提问于
浏览
16

这个问题在这里已有答案:

Monad变换器以所有标准monad(Reader,Writer,State,Cont,List等)而闻名,但这些monad变换器中的每一个都以稍微不同的方式工作 . 在给定具有monad实例的类型构造函数的定义的情况下,没有用于构造monad变换器的通用方法或公式 . 因此,不能保证根据某些任意业务要求设计的monad数据类型将具有monad变换器 . 有没有这样一个明确的例子?

相关工作

Another question解释说,两个monad的仿函数组合不一定是monad . 另见this question . 这些例子没有回答当前的问题 - 它们仅仅说明了没有构造单子变压器的一般方法的问题 . 这些例子表明,给定两个单子M和N,我们有时会发现M(N a)是单子,有时N(M a)是单子,有时也不是单子 . 但这既没有说明如何为M或N构造monad变换器,也没有表明它是否存在 .

An answer to another question认为 IO monad不能有monad变换器,因为如果它有一个 IOT ,我们可以将 IOT 应用于 List ,然后将空列表( lift [] )提升到生成的monad中,必须撤消IO执行的副作用"earlier"单子 . 这个论点是基于这样的想法,即可能无法撤消的副作用 . 但是, IO monad不是显式类型构造函数 .

讨论

在明确给出monad类型的每个例子中,可以以某种方式找到monad变换器, - 有时需要一定的独创性 . 例如,Haskell库中存在的 ListT 变换器被发现是错误的,但最终通过更改 ListT 的定义来解决问题 .

没有变换器的monad的标准示例是monad,例如 IO ,它实际上不是由显式类型构造函数定义的 - IO 是由库以某种方式在低级别定义的不透明"magic"类型 . 很明显,人们不能将 IO 定义为显式类型构造函数,并且纯函数给出了monad实例 . IO 示例显示如果我们允许monad实例包含具有不纯副作用的隐藏低级代码,则monad转换器可能无法存在 . 所以,让我们将注意力限制在使用纯函数实现的monad上 .

似乎没有一种算法可以从monad的源代码中自动导出monad变换器 . 我们甚至知道这总是可能的吗?

为了让我更清楚一个monad的“明确例子”我的意思:假设我声称

type Q u v a = ((u -> (a, Maybe a)) -> v) -> u -> (a, Maybe a)

可以有一个关于类型参数 a 的合法 Monad 实例,并且为 Q u v 生成 Monad 实例的实现的源代码,作为纯函数 returnjoin . 那么我们知道 Q u v 有一个monad变压器 QT u v 这样 QT u v Id 相当于 Q u v ,monad变压器的定律是什么?那么我们知道如何明确地构建 QT 吗?我不 .

要决定这个问题,我们需要

  • 演示一种算法,该算法可以从任意给定类型构造函数和monad实例的给定实现中找到monad变换器;例如给出代码 type F a = r -> Either (a, a) (a, a, Maybe a) 并为此实现monad实例,找到monad变换器的代码;为了简单起见,我们将自己限制为使用 -> ,tuple和 Either 的任意组合构造的构造函数;要么

  • 演示一个反例:一个显式的monad类型构造函数,由显式代码定义给出,例如: type F a = r -> Either (a, a, a) (a, a, Maybe a) 或其他什么,这是一个合法的 Monad ,由纯函数给出 Monad 实例,但我们可以证明 F 没有monad变换器 .

1 回答

  • 1

    这不是一个答案,但它对评论来说太大了 . 我们可以写

    {-# LANGUAGE GeneralizedNewtypeDeriving
      , DeriveFunctor #-}
    
    import Control.Monad.Free
    
    -- All the IO primops you could ever need
    data IOF a = PutStrLn String a
               | GetLine (String -> a)
               deriving Functor
    
    newtype MyIO a = MyIO {unMyIO :: Free IOF a}
      deriving (Functor, Applicative, Monad)
    

    但我们实际上可以制作一个monad变换器:

    import Control.Monad.Trans.Free
    
    newtype IOT m a = IOT {unIOT :: FreeT IOF m a}
      deriving (Functor, Applicative, Monad, MonadTrans)
    

    所以我并不认为即使 IO 被排除在外,尽管那种情况下的同构不是"internal" .

相关问题