尝试实现 (>>=) 函数以创建自定义 monad 转换器时出现类型错误

发布于 2024-08-29 06:55:18 字数 1290 浏览 13 评论 0原文

我正在尝试为未来的项目创建一个 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 monad 中运行。因此,runRuntimeT x >>>= 返回一个 Runtime a 类型的值(对吗?)。然后,以下代码 id >>= 应返回 a 类型的值。该值被传递给类型为 f :: (Monad m) => 的函数 f一个->运行时T 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。

I'm trying to create a monad transformer for a future project, but unfortunately, my implementation of the Monad typeclasse's (>>=) function doesn't work.

First of all, here is the underlying monad's implementation :

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

Here, the implementation of the Monad typeclasse is done automatically by GHC (using the GeneralizedNewtypeDeriving language pragma).
The monad transformer is defined as so :

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

The problem comes from the way I instanciate the (>>=) function of the Monad typeclasse :

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

The way I see it, the first >>= runs in the underlying m monad. Thus, runRuntimeT x >>= returns a value of type Runtime a (right ?). Then, the following code, id >>=, should return a value of type a. This value is the passed on to the function f of type f :: (Monad m) => a -> RuntimeT m b.

And here comes the type problem : the f function's type doesn't match the type required by the (>>=) function. Jow can I make this coherent ? I can see why this doesn't work, but I can't manage to turn it into something functionnal.

Edit : The error message :

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.

Thank you for you help, and do not hesitate to correct any flaws in my message,
Charlie P.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谁的新欢旧爱 2024-09-05 06:55:18

通常的 StateT s m monad 将 a 发送到 s -> m (a, s) 但您正在使用 m (s -> (a, s)) 来代替。我不认为后者形成了通用 s 的 monad。您确定不想只使用 StateT 吗?


这就是为什么我不认为 am (s -> (a, s)) 是一个 monad:要写 >>=< /code> 我需要一个接受类型参数

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

并返回类型值的

m (s -> (b, s))

函数 结果的“效果”(即 fmap (const ()))必须是第一个参数的效果,因为我们无法将 a 传递给第二个参数。由于 m 仅出现在结果类型的外部,因此我们根本无法将第二个参数用于任何内容 - 将无法摆脱 m 它介绍。

The usual StateT s m monad sends a to s -> m (a, s) but you are working with m (s -> (a, s)) instead. I don't think the latter forms a monad for general s. Are you sure you don't just want to use StateT?


Here's why I don't think am (s -> (a, s)) is a monad: To write >>= I need a function that takes arguments of types

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

and returns a value of type

m (s -> (b, s))

The "effects" (i.e. fmap (const ())) of the result must be those of the first argument, since we have no way to get an a to pass to the second argument. Since m appears only on the outside of the result type, we then cannot use the second argument for anything at all—there will be no way to get rid of the m it introduces.

明媚殇 2024-09-05 06:55:18

继续 Reid Barton 关于 StateT 的说法 - 以下是如何使用 StateT 定义 RuntimeT。然后可以使用标识 monad 简单地定义运行时 monad。

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)

To follow on from what Reid Barton said about StateT - here's how you would define RuntimeT using StateT. The Runtime monad can then be trivially defined using the identity monad.

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文