为什么 httpJSON 失败,而 httpLBS 成功?

Why does httpJSON fail, but httpLBS succeeds?

此功能(使用 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.

比较httpLBShttpJSON的类型:

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

请注意 httpLBS 总是 生成 Response ByteString,但 httpLBS 生成 Response a。这是什么意思?

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

决定

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

ghci> id True
True

即使 id 函数的类型为 a -> a,GHC 也可以推断出 a 显然只有 一个 选项,Bool,所以选择了。但是,考虑一下您的程序——GHC 怎么知道 a 应该是什么? response 结果仅用在一个地方,getResponseStatusCode,具有以下类型签名:

getResponseStatusCode :: Response a -> Int

这个函数也适用于 any Response a,所以 GHC 仍然不能决定 a 应该是什么:根据 GHC 的术语, a 变量 不明确 。问题是必须为 a 选择特定类型,因为它需要知道使用哪个 FromJSON 实例来解析响应主体。

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

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

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

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

λ makeRequest
200
it :: ()