Почему 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 -> aGHC может сделать вывод, что существует только один выбор 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 :: ()
Другие вопросы по тегам