此功能(使用 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.
最佳答案
比较httpLBS
的类型和 httpJSON
:
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
此功能也适用于任何
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 结构。
关于haskell - 为什么 httpJSON 失败,但 httpLBS 成功?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46694290/