为什么httpJSON失败,但httpLBS成功?
问题描述:
此功能(与httpLBS)工作原理:为什么httpJSON失败,但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
应该是什么?
getResponseStatusCode :: Response a -> Int
此功能也适用于任何Response a
,因此GHC仍然无法决定a
应该是什么:该response
结果只在一个地方,getResponseStatusCode
,它具有以下类型签名用于根据以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的结构。
谢谢你这样一个惊人的答案。它的作品,它帮助我理解为什么! – TomDane