定义一个函数时不使用任何语言扩展,但必须使用语言扩展来声明其类型?
我定义了一个自定义错误类型,我想将其与错误单子一起使用。举个例子,这里有一个虚拟的:
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于您使用的是
Error
monad,因此您已经依赖于扩展,尤其是MultiParamTypeClasses
和FunctionalDependency
,所以我不确定尝试保持代码无扩展是有意义的。有些扩展可能会产生一些潜在的令人讨厌的副作用(例如
IncoherentInstances
),并且将这些扩展的使用保持在最低限度当然是有必要的,但是像FlexibleContexts
这样的扩展是完全无害。Since you're using the
Error
monad, you're already relying on extensions, most notablyMultiParamTypeClasses
andFunctionalDependencies
, 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 likeFlexibleContexts
are completely harmless.