简体   繁体   English

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

[英]Why does httpJSON fail, but httpLBS succeeds?

This function (with httpLBS) works: 此功能(使用httpLBS)有效:

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

But this function (with httpJSON) does not: 但是这个函数(使用httpJSON)不会:

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

It throws the error: 它抛出错误:

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.

Compare the types of httpLBS and httpJSON : 比较httpLBShttpJSON的类型:

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

Notice that httpLBS always produces a Response ByteString , but httpLBS produces Response a . 请注意, httpLBS 始终生成Response ByteString ,但httpLBS生成Response a What does that mean? 这意味着什么?

In this case, it means that httpJSON can produce a Response containing anything at all with a FromJSON instance, and it's up to the function's caller to decide. 在这种情况下,这意味着httpJSON可以使用FromJSON实例生成包含任何内容的Response ,并且由函数的调用者决定。 How does the caller decide? 来电者如何决定? By specifying the type! 通过指定类型! This is one of the most interesting properties of Haskell's typeclasses: the behavior of your program is determined by its types . 这是Haskell的类型类中最有趣的属性之一:程序的行为由其类型决定。

Of course, most of the time, you don't see those types, because they are inferred. 当然,大多数时候,你没有看到那些类型,因为它们是推断的。 For example, if you write the following program, you will not need to write any type annotations: 例如,如果编写以下程序,则无需编写任何类型的注释:

ghci> id True
True

Even though the id function has type a -> a , GHC can infer that there is clearly only one choice for a , Bool , so it is chosen. 即使id函数具有类型a -> a ,GHC也可以推断出aBool只有一个选择,所以选择它。 However, consider your program—how can GHC know what a is supposed to be? 然而,考虑你的程序如何GHC知道什么是a应该是? The response result is only used in one place, getResponseStatusCode , which has the following type signature: response结果仅在一个地方使用, getResponseStatusCode ,具有以下类型签名:

getResponseStatusCode :: Response a -> Int

This function also works on any Response a , so GHC still can't decide what the a should be: according to GHC's terminology, the a variable is ambiguous . 此函数也适用于任何 Response a ,因此GHC仍然无法确定a应该是什么:根据GHC的术语, a变量是不明确的 The trouble is that picking a specific type for a is necessary, since it needs to know which FromJSON instance to use to parse the response body. 问题是为a选择特定类型是必要的,因为它需要知道使用哪个FromJSON实例来解析响应主体。

In order to solve this problem, you can disambiguate the expression by supplying your own type annotation, forcing GHC to pick a particular type for a : 为了解决这个问题,你可以通过提供自己的类型注释,迫使GHC选择一个特定类型的歧义表达a

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

Of course, you should replace () with whatever type represents the structure of the JSON you expect the response to produce. 当然,你应该用任何代表你希望响应产生的JSON结构的类型替换()

Not sure if this is helpful for anyone else but it helped me. 不确定这是否对其他人有帮助,但它帮助了我。 I tried the ::IO (Response ()) annotation and I was getting back the full printed response and then "expected (), encountered Object" , and switching it to :: IO (Response Object) fixed it to simply output 我尝试了::IO (Response ())注释,我得到了完整的打印响应然后"expected (), encountered Object" ,并将其切换到:: IO (Response Object)修复它只是输出

λ makeRequest
200
it :: ()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM