3

我正在尝试为未来的项目创建一个 monad 转换器,但不幸的是,我对 Monad 类型类 (>>=) 函数的实现不起作用。

首先,这是底层 monad 的实现:

newtype Runtime a = R { 
  unR :: State EInfo a
} deriving (Monad)

在这里,Monad 类型类的实现由 GHC 自动完成(使用GeneralizedNewtypeDeriving语言 pragma)。monad 转换器定义如下:

newtype RuntimeT m a = RuntimeT {
  runRuntimeT :: m (Runtime a)
} 

问题来自我实例化 Monad typeclasse 的 (>>=) 函数的方式:

instance (Monad m) => Monad (RuntimeT m) where
    return a = RuntimeT $ (return . return) a
    x >>= f =  runRuntimeT x >>= id >>= f

在我看来,第一个>>=在底层m单子中运行。因此,runRuntimeT x >>=返回一个类型的值Runtime a(对吗?)。然后,下面的代码 ,id >>=应该返回一个 type 的值a。该值被传递给类型为 f 的函数f :: (Monad m) => a -> RuntimeT m b

这里出现了类型问题:f函数的类型与 (>>=) 函数所需的类型不匹配。我能让这个连贯吗?我明白为什么这不起作用,但我无法将它变成功能性的东西。

编辑:错误信息:

Core.hs:34:4:
    Occurs check: cannot construct the infinite type: m = RuntimeT m
    When generalising the type(s) for `>>='
    In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.

感谢您的帮助,并毫不犹豫地纠正我信息中的任何缺陷,
查理 P。

4

2 回答 2

4

通常的StateT s m单子发送a到,s -> m (a, s)但您正在使用m (s -> (a, s))。我不认为后者形成了 general 的单子s。你确定你不只是想使用StateT


这就是为什么我不认为am (s -> (a, s))是一个单子:要编写>>=我需要一个接受类型参数的函数

m (s -> (a, s))
a -> m (s -> (b, s))

并返回一个类型的值

m (s -> (b, s))

结果的“效果”(即fmap (const ()))必须是第一个参数的效果,因为我们无法将 ana传递给第二个参数。由于m仅出现在结果类型的外部,因此我们根本不能将第二个参数用于任何东西——将无法摆脱m它引入的。

于 2010-04-18T14:43:36.170 回答
3

继续 Reid Barton 所说的StateT- 这是您如何定义RuntimeTusing StateT. 然后Runtime可以使用身份单子轻松定义单子。

newtype RuntimeT m a = R { 
  unR :: StateT EInfo m a
}

type Runtime = RuntimeT Identity

instance Monad m => Monad (RuntimeT m) where
    return = R . return

    (R m) >>= f = R (m >>= unR . f)
于 2010-04-18T23:58:38.127 回答