代码之家  ›  专栏  ›  技术社区  ›  Benjamin Hodgson

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

  •  13
  • Benjamin Hodgson  · 技术社区  · 11 年前

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

    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
    

    换句话说,此函数可以返回满足这两个条件的任何monad MonadIO 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 语言扩展以使此代码正常工作。什么是 灵活的上下文 是的,是吗 真正地 对我来说是必要的吗?我不想在不知道是否需要的情况下随意打开语言扩展。

    如果不使用类型签名,该函数可以很好地编译,但我不希望这样做。

    1 回复  |  直到 11 年前
        1
  •  22
  •   Dan    11 年前

    Haskell 98不允许 MonadError Failure m ,他们必须看起来像 MonadError a m 然而,GHC增加了具有类似约束的能力,这就是该扩展所做的。我理解对语言扩展的警惕,但FlexibleContexts是无害的。

    我相信,在Haskell98问世时,使用这种约束的类型理论还没有开发出来,但从那时起,它已经开发出来了。扩展在使用该理论的类型检查器中打开一些额外的代码。如果你搜索一下,你可能会找到一篇关于它是如何工作的论文。