2017-10-11 102 views
2

此功能(与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. 

回答

9

比较类型httpLBShttpJSON

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

注意httpLBS总是产生Response ByteString,但httpLBS产生Response a。那是什么意思?

在这种情况下,这意味着httpJSON可以在任何产生含有任何ResponseFromJSON实例,它是由函数的调用者决定。来电者如何决定?通过指定类型!这是Haskell的类特性中最有趣的属性之一:程序的行为取决于它的类型

当然,大多数情况下,您不会看到这些类型,因为它们是推断的。例如,如果你写了下面的程序,你不需要写任何类型的注释:

ghci> id True 
True 

即使id函数的类型是a -> a,GHC可以推断,显然只有一个选择。aBool,所以选择它。但是,考虑你的计划 - 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的结构。

+0

谢谢你这样一个惊人的答案。它的作品,它帮助我理解为什么! – TomDane

相关问题