5

此功能(使用 httpLBS)有效:

makeRequest = do
  response <- httpLBS "http://httpbin.org/get" 
  putStrLn $ "The status code was: " ++ show (getResponseStatusCode response)

但是这个函数(使用 httpJSON)没有:

makeRequest = do
  response <- httpJSON "http://httpbin.org/get" 
  putStrLn $ "The status code was: " ++ show (getResponseStatusCode response)

它抛出错误:

Ambiguous type variable `a0' arising from a use of `httpJSON' prevents the constraint 
`(aeson-1.1.2.0:Data.Aeson.Types.FromJSON.FromJSON a0)' from being solved.
          Probable fix: use a type annotation to specify what `a0' should be.
4

2 回答 2

15

比较 和 的httpLBS类型httpJSON

httpLBS ::   MonadIO m              => Request -> m (Response ByteString)
httpJSON :: (MonadIO m, FromJSON a) => Request -> m (Response a         )

请注意,它httpLBS 总是产生 a Response ByteString,但httpLBS产生Response a。这意味着什么?

在这种情况下,这意味着httpJSON可以产生一个Response包含任何东西的FromJSON实例,这取决于函数的调用者来决定。来电者如何决定?通过指定类型!这是 Haskell 类型类最有趣的属性之一:程序的行为由它的类型决定。

当然,大多数时候,您看不到这些类型,因为它们是推断出来的。例如,如果您编写以下程序,则不需要编写任何类型注释:

ghci> id True
True

即使id函数有 type a -> a,GHC 也可以推断出 , 显然只有一个选择aBool因此被选中。然而,考虑一下你的程序——GHC 怎么知道a应该是什么?结果response仅在一个地方使用getResponseStatusCode,它具有以下类型签名:

getResponseStatusCode :: Response a -> Int

此函数也适用于any Response a,因此 GHC 仍然无法确定a应该是什么:根据 GHC 的术语,a变量是ambiguous。问题是选择特定类型a是必要的,因为它需要知道FromJSON使用哪个实例来解析响应正文。

为了解决这个问题,您可以通过提供自己的类型注释来消除表达式的歧义,强制 GHC 为 选择特定类型a

makeRequest = do
  response <- httpJSON "http://httpbin.org/get" :: IO (Response ())
  putStrLn $ "The status code was: " ++ show (getResponseStatusCode response)

当然,您应该替换()为代表您期望响应产生的 JSON 结构的任何类型。

于 2017-10-11T17:48:22.377 回答
0

不确定这是否对其他人有帮助,但它帮助了我。我尝试了::IO (Response ())注释,然后我得到了完整的打印响应,然后"expected (), encountered Object"将其切换为:: IO (Response Object)修复它以简单地输出

λ makeRequest
200
it :: ()
于 2019-03-13T20:05:33.250 回答