约束中的非类型变量参数:MonadError Failure m

Ben*_*son 12 haskell monad-transformers

我已经定义了一个自定义错误类型:

data Failure = NetworkError Message |
               UserIsTooStupid Message |
               InvalidOperation Message |
               UnexpectedError Message
type Message = String
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用MonadError我的错误类型:

loadJSON :: (Aeson.FromJSON v, MonadIO m, MonadError Failure m) => URI -> m v
loadJSON uri = do
    body <- liftIO $ getResponseBody =<< simpleHTTP (getRequest uri)
    case Aeson.decode body of
         Just json -> return json
         Nothing -> throwError $ SerialisationError "Couldn't deserialise from JSON"

type URI = String
Run Code Online (Sandbox Code Playgroud)

换句话说,这个函数可以返回它同时满足任何单子MonadIOMonadError,但错误的它可以抛出的唯一类型Failure.

这无法编译,错误消息:

Non type-variable argument in the constraint: MonadError Failure m
(Use -XFlexibleContexts to permit this)
In the type signature for `loadJSON':
  loadJSON :: (Aeson.FromJSON v, MonadIO m, MonadError Failure m) =>
              URI -> m v
Run Code Online (Sandbox Code Playgroud)

GHC希望我打开FlexibleContexts语言扩展来使这段代码工作.做FlexibleContexts什么,在我的情况下真的有必要吗?我不想在不知道我是否需要语言扩展的情况下不打开语言扩展.

如果我省略类型签名,该函数编译良好,但我不想这样做.

Dan*_*Dan 20

Haskell 98不允许看起来像这样的约束MonadError Failure m,它们必须看起来像MonadError a m.然而,具有这种约束的能力被添加到GHC,这就是扩展所做的.我理解对语言扩展保持警惕,但FlexibleContexts非常无害.

我相信在Haskell 98出现的时候,使用类似约束的类型理论还没有开发出来,但从那时起它就有了.扩展在类型检查器中打开了一些使用该理论的额外代码.如果你稍微谷歌,你可能会找到一篇关于它是如何工作的论文.

  • 从某种意义上讲,它不会改变不使用该扩展的程序的含义,并为那些使用它的人赋予"明智的"含义,这是无害的.其他一些扩展例如"IncoherentInstances"被认为是潜在有害的,因为利用它们的程序具有棘手的语义,因此很难推理. (5认同)
  • 你能详细说明一下语言扩展的作用吗?在什么意义上它是无害的?为什么Haskell 98不允许这种类型的签名? (2认同)