我定义了一个自定义错误类型,我想将其与错误单子(monad)一起使用。为了举例,这里有一个虚拟的:
newtype CustomError = CustomError String
instance Error CustomError where
strMsg = CustomError
我想定义一个 throwCustomError
函数,其工作方式类似于 throwError
,但它不只是抛出给定的字符串,而是使用它来创建一个 CustomError
,然后抛出那个。这个定义有效:
-- | Throws a 'CustomError' containing the given error message.
throwCustomError msg = throwError $ CustomError msg
但是,我想添加一个类型声明,主要是为了让 Haddock 在生成的文档中包含函数的描述。如果我在 GHCI 中使用 :t
,它会告诉我这个函数的类型是 MonadError CustomError m => String -> m a
,这对我来说很有意义,但是如果我写
throwCustomError :: MonadError CustomError m => String -> m a
GHC 提示“非变量类型参数”,并告诉我必须使用 -XFlexibleContexts
来允许它。当我可以定义这种类型的函数而无需使用任何语言扩展时,为什么我必须使用语言扩展来声明这种类型的函数?有没有办法在不使用语言扩展的情况下声明该函数的类型?
另外,我最初尝试将函数定义为
throwCustomError = throwError . CustomError
但是 GHC 告诉我“没有因使用 throwError
而产生的 (MonadError CustomError m0)
实例”。我不太明白为什么这个定义与另一个定义不等价;据我所知,它们的含义相同。
退后一步:我是否应该定义这个函数?或者当我想抛出错误时我应该只写 throwError $ strMsg "foo"
吗? (目前我的代码中有 throwError "foo"
,所以我需要以任何方式更改这些行。)
最佳答案
由于您正在使用 Error
monad,你已经依赖扩展了,最值得注意的是 MultiParamTypeClasses
和FunctionalDependencies
,所以我不确定尝试保持代码无扩展是否有任何意义。
有些扩展可能会产生一些潜在的令人讨厌的副作用(例如 IncoherentInstances
),并且将这些扩展的使用量保持在最低限度当然是有必要的,但是像 FlexibleContexts
这样的扩展完全无害。
关于haskell - 定义一个函数时不使用任何语言扩展,但必须使用语言扩展来声明其类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9223338/