定义一个函数时不使用任何语言扩展,但必须使用语言扩展来声明其类型?

发布于 2025-01-04 23:23:18 字数 1280 浏览 2 评论 0原文

我定义了一个自定义错误类型,我想将其与错误单子一起使用。举个例子,这里有一个虚拟的:

newtype CustomError = CustomError String
instance Error CustomError where
  strMsg = CustomError

我想定义一个像 throwError 一样工作的 throwCustomError 函数,但它不只是抛出给定的字符串,而是使用它创建一个 CustomError,然后抛出 that。这个定义有效:

-- | Throws a 'CustomError' containing the given error message.
throwCustomError msg = throwError $ CustomError msg

但是,我想添加一个类型声明,主要是为了让 Haddock 在生成的文档中包含函数的描述。如果我在 GHCI 中使用 :t ,它会告诉我这个函数的类型是 MonadError CustomError m =>字符串 -> m a,这对我来说很有意义,但是如果我写

throwCustomError :: MonadError CustomError m => String -> m a

GHC 会抱怨“非变量类型参数”,并告诉我必须使用 -XFlexibleContexts 来允许它。当我可以定义这种类型的函数而无需使用任何语言扩展时,为什么我必须使用语言扩展来声明这种类型的函数?有没有办法在不使用语言扩展的情况下声明该函数的类型?


另外,我最初尝试将函数定义为

throwCustomError = throwError . CustomError

但 GHC 告诉我“没有因使用 throwError 而产生的 (MonadError CustomError m0) 实例”。我不太明白为什么这个定义与另一个定义不等价;据我所知,它们的含义相同。


退一步:我是否应该定义这个函数?或者当我想抛出错误时,我应该只写 throwError $ strMsg "foo" 吗? (目前我的代码中有 throwError "foo" ,所以我需要以任何方式更改这些行。)

I've defined a custom error type that I want to use with the Error monad. For the sake of example, here's a dummy one:

newtype CustomError = CustomError String
instance Error CustomError where
  strMsg = CustomError

I'd like to define a throwCustomError function that works like throwError, but instead of just throwing the string it's given, it uses it to create a CustomError and then throws that. This definition works:

-- | Throws a 'CustomError' containing the given error message.
throwCustomError msg = throwError $ CustomError msg

However, I'd like to add a type declaration, mainly so that Haddock will include the function's description in the generated documentation. If I use :t in GHCI, it tells me that the type of this function is MonadError CustomError m => String -> m a, and that makes sense to me, but if I write

throwCustomError :: MonadError CustomError m => String -> m a

GHC complains about a "non-variable type argument" and tells me I have to use -XFlexibleContexts to permit it. Why do I have to use a language extension to declare a function of this type, when I can define a function of this type without using any language extensions? Is there a way to declare this function's type without using language extensions?


On a separate note, I originally tried defining the function as

throwCustomError = throwError . CustomError

but GHC tells me "No instance for (MonadError CustomError m0) arising from a use of throwError". I don't quite understand why this definition isn't equivalent to the other one; they both mean the same thing as far as I can see.


Taking a step back: should I even bother defining this function? Or should I just write throwError $ strMsg "foo" when I want to throw an error? (Currently I have throwError "foo" throughout my code, so I need to change those lines either way.)

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

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

发布评论

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

评论(1

柳絮泡泡 2025-01-11 23:23:18

由于您使用的是 Error monad,因此您已经依赖于扩展,尤其是 MultiParamTypeClassesFunctionalDependency,所以我不确定尝试保持代码无扩展是有意义的。

有些扩展可能会产生一些潜在的令人讨厌的副作用(例如 IncoherentInstances),并且将这些扩展的使用保持在最低限度当然是有必要的,但是像 FlexibleContexts 这样的扩展是完全无害。

Since you're using the Error monad, you're already relying on extensions, most notably MultiParamTypeClasses and FunctionalDependencies, so I'm not sure that there is any point in trying to keep your code extension-free.

There are some extensions which have some potentially nasty side-effects (e.g. IncoherentInstances), and there's certainly a point to keeping usage of those to a minimum, but extensions like FlexibleContexts are completely harmless.

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