2017-10-11 160 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

相關問題