Почему httpJSON терпит неудачу, а httpLBS успешно?
Эта функция (с 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.
1 ответ
Сравните типы 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
должно быть? 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, вы ожидаете получить ответ.
Not sure if this is helpful for anyone else but it helped me. I tried the ::IO (Response ())
annotation and I was getting back the full printed response and then "expected (), encountered Object"
, and switching it to :: IO (Response Object)
fixed it to simply output
λ makeRequest
200
it :: ()