尝试实现 (>>=) 函数以创建自定义 monad 转换器时键入错误
-
27-09-2019 - |
题
我正在尝试为未来的项目创建一个 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
单子发送 a
到 s -> m (a, s)
但你正在与 m (s -> (a, s))
反而。我不认为后者形成了一般的单子 s
. 。您确定不只是想使用 StateT
?
这就是为什么我不认为 a
→ m (s -> (a, s))
是一个单子:来写 >>=
我需要一个接受类型参数的函数
m (s -> (a, s))
a -> m (s -> (b, s))
并返回一个类型的值
m (s -> (b, s))
“效果”(即 fmap (const ())
)的结果必须是第一个参数的结果,因为我们无法获得 a
传递到第二个参数。自从 m
只出现在结果类型的外部,那么我们就不能将第二个参数用于任何东西——没有办法摆脱 m
它介绍了。