2017-10-11 3 views
2

Cette fonction (avec httpLBS) fonctionne:Pourquoi httpJSON échoue, mais httpLBS réussit?

makeRequest = do 
    response <- httpLBS "http://httpbin.org/get" 
    putStrLn $ "The status code was: " ++ show (getResponseStatusCode response) 

Mais cette fonction (avec httpJSON) n'a pas:

makeRequest = do 
    response <- httpJSON "http://httpbin.org/get" 
    putStrLn $ "The status code was: " ++ show (getResponseStatusCode response) 

Il jette l'erreur:

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. 

Répondre

9

Comparer les types de httpLBS et httpJSON:

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

Notez que httpLBStoujours produit un Response ByteString, mais httpLBS produit Response a. Qu'est-ce que ça veut dire?

Dans ce cas, cela signifie que httpJSON peut produire un Response tout ce qui contient du tout avec une instance FromJSON, et il est à appelant de la fonction de décider. Comment l'appelant décide-t-il? En spécifiant le type! C'est l'une des propriétés les plus intéressantes des typeclasses de Haskell: le comportement de votre programme est déterminé par ses types.

Bien sûr, la plupart du temps, vous ne voyez pas ces types, car ils sont inférés. Par exemple, si vous écrivez le programme suivant, vous aurez pas besoin d'écrire des annotations de type:

ghci> id True 
True 

Même si la fonction id est de type a -> a, GHC peut en déduire qu'il n'y a manifestement que un choix pour a , Bool, donc il est choisi. Cependant, considérez votre programme - comment GHC peut-il savoir ce que doit être a? Le résultat response est utilisé que dans un seul endroit, getResponseStatusCode, qui a la signature de type:

getResponseStatusCode :: Response a -> Int 

Cette fonction fonctionne également sur touteResponse a, donc GHC ne peut toujours pas décider ce que le a devrait être: selon à la terminologie de GHC, la variable a est ambiguë. Le problème est que choisir un type spécifique pour a est nécessaire, car il doit savoir quelle instance FromJSON utiliser pour analyser le corps de la réponse.

Pour résoudre ce problème, vous pouvez désambiguïser l'expression en fournissant votre propre annotation de type, ce qui oblige GHC à choisir un type particulier pour a:

makeRequest = do 
    response <- httpJSON "http://httpbin.org/get" :: IO (Response()) 
    putStrLn $ "The status code was: " ++ show (getResponseStatusCode response) 

Bien sûr, vous devez remplacer () avec quel type représente la structure du JSON que vous attendez de la réponse.

+0

Merci pour cette réponse incroyable. Cela fonctionne, et cela m'aide à comprendre pourquoi! – TomDane