此函数(使用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
可以通过FromJSON
实例生成包含任何内容的Response
,这取决于函数的调用者。打电话的人是如何决定的?通过指定类型!这是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结构的任何类型。
不确定这是否对其他人有帮助,但它对我有帮助。我尝试了::IO (Response ())
注释,得到了完整的打印响应,然后是"expected (), encountered Object"
,并将其切换到:: IO (Response Object)
修复了它,只需输出
λ makeRequest
200
it :: ()