Я пытаюсь написать парсер JSON с помощью Aeson.
То, как я вызываю JSON в своем коде:
testReq :: Request
testReq = parseRequest_ "https://api.openweathermap.org/data/2.5/onecall?lat=41.63526&lon=-70.92701&exclude=minutely&appid=93120a85abf28f8fb1cdae14ffd7435d&units=metric"
Сначала я определяю свой собственный тип
type Celsius = Double
type HPA = Int --Hectopascal Pressure Unit
type Percent = Int
type Meter = Int
type MeterPerSec = Double
type CompassDegree = Int
data WeatherObj =
WeatherObj
{ time :: UTCTime
, temp :: Celsius
, feels_like :: Celsius
, pressure :: HPA
, humidity :: Percent
, visibility :: Meter
, wind_speed :: MeterPerSec
, wind_deg :: CompassDegree
}
deriving (Eq, Show, Generic)
Затем я пишу свой экземпляр FromJSON, который, как я знаю, работает, потому что если я запускаю parseCurrentWeather testReq
, я получаю обратно WeatherObj {time = 2020-07-19 16:54:43 UTC, temp = 25.51, feels_like = 29.49, pressure = 1012, humidity = 83, visibility = 10000, wind_speed = 1.34, wind_deg = 247}
И это прекрасно!
instance FromJSON WeatherObj where
parseJSON = withObject "weatherObj" $ \obj -> do
timeOffset <- obj .: "timezone_offset"
currentO <- obj .: "current"
dt <- currentO .: "dt"
temp <- currentO .: "temp"
feels_like <- currentO .: "feels_like"
pressure <- currentO .: "pressure"
humidity <- currentO .: "humidity"
visibility <- currentO .: "visibility"
wind_speed <- currentO .: "wind_speed"
wind_deg <- currentO .: "wind_deg"
pure $ WeatherObj (makeLocalTime dt timeOffset)
temp feels_like
pressure humidity
visibility wind_speed
wind_deg
parseCurrentWeather :: Request -> IO WeatherObj
parseCurrentWeather req = do
current <- fetchCurrentWeather req
pure $ getResponseBody current
Теперь мне нужно выяснить, как анализировать почасовую погоду, которая должна вернуть мне 48 объектов. Этот код работает так, как если бы я запускал parseHourly testReq
, я возвращал длинную строку JSON без исключений. Этот JSON определенно соответствует JSON из ссылки. Я отлично выгляжу до этого момента.
fetchHourly :: Request -> IO (Response HourlyWeathers) --Could also be IO (Response Object)
fetchHourly = httpJSON
data HourlyWeathers =
HourlyWeathers
{ getHours :: [Object] }
deriving (Eq, Show, Generic)
instance FromJSON HourlyWeathers where
parseJSON = withObject "hourlyWeather" $ \obj -> do
allHours <- obj .: "hourly"
pure $ HourlyWeathers allHours
parseHourly :: Request -> IO HourlyWeathers
parseHourly req = do
hours <- fetchHourly req
pure $ getResponseBody hours
Теперь мы находимся в проблемном коде. Я хотел бы сопоставить objToWeatherObj
со списком объектов, которые я генерирую с помощью parseHourly
. Проблема, которую я не могу решить, заключается в том, что когда я запускаю parseHourlyObjects
, я получаю список всех Ничего.
parseHourlyObjects :: Request -> IO [Maybe WeatherObj]
parseHourlyObjects req = do
hourly <- fetchHourly req
let x = getHours $ getResponseBody hourly
y = fmap objToWeatherObj x
pure y
objToWeatherObj :: Object -> Maybe WeatherObj
objToWeatherObj = (decode . encode)
Я смог написать экземпляр ToJSON
для WeatherObj
, но это оказалось неуместным, потому что мне нужно преобразовать общий Object
в WeatherObj
. Я считаю, что мне нужна функция decode
, хотя я могу ошибаться.