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

时间:2014-04-01 20:01:46

标签: haskell monad-transformers

我已定义了自定义错误类型:

data Failure = NetworkError Message |
               UserIsTooStupid Message |
               InvalidOperation Message |
               UnexpectedError Message
type Message = String

我正在尝试将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

换句话说,此函数可以返回满足MonadIOMonadError的任何monad,但它可以抛出的唯一错误类型是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

GHC希望我打开FlexibleContexts语言扩展程序以使此代码正常工作。 FlexibleContexts做了什么,在我的案例中真的是否必要?我不想在不知道是否需要语言扩展的情况下不打开语言扩展。

如果我不使用类型签名,该函数编译正常,但我不想这样做。

1 个答案:

答案 0 :(得分:20)

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

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