为什么httpJSON失败,但httpLBS成功了?

时间:2017-10-11 17:31:29

标签: haskell http-conduit

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

2 个答案:

答案 0 :(得分:11)

比较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也可以推断aBool只有一个选项,所以它被选中了。但是,考虑一下你的程序 - GHC如何知道a应该是什么? response结果仅用于一个地方getResponseStatusCode,其中包含以下类型签名:

getResponseStatusCode :: Response a -> Int

此功能也适用于任何 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结构的任何类型替换()

答案 1 :(得分:0)

不确定这是否对其他人有帮助,但对我有帮助。我尝试使用::IO (Response ())批注,然后返回完整的打印响应,然后返回"expected (), encountered Object",并将其切换为:: IO (Response Object)使其固定为仅输出

λ makeRequest
200
it :: ()