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



此函数(使用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可以通过FromJSON实例生成包含任何内容的Response,这取决于函数的调用者。打电话的人是如何决定的?通过指定类型!这是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结构的任何类型。

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

λ makeRequest
200
it :: ()

相关内容

  • 没有找到相关文章

最新更新