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

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

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

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

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

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

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 >>=, ,应该返回一个类型的值 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。

有帮助吗?

解决方案

要从什么雷德巴顿说约StateT遵循 - 这里就是你将如何使用RuntimeT定义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)

其他提示

通常 StateT s m 单子发送 as -> m (a, s) 但你正在与 m (s -> (a, s)) 反而。我不认为后者形成了一般的单子 s. 。您确定不只是想使用 StateT?


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

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

并返回一个类型的值

m (s -> (b, s))

“效果”(即 fmap (const ()))的结果必须是第一个参数的结果,因为我们无法获得 a 传递到第二个参数。自从 m 只出现在结果类型的外部,那么我们就不能将第二个参数用于任何东西——没有办法摆脱 m 它介绍了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top