我正在编写一个小型库,用于与几个外部API进行交互。其中一组函数将构建一个有效的请求到Yahoo API,并解析结果到一个数据类型中。另一组函数将根据IP查找用户当前位置,并返回表示当前位置的数据类型。虽然代码可以工作,但似乎必须显式地模式匹配以对多个类型为IO (Maybe a)的函数进行排序。
-- Yahoo API
constructQuery :: T.Text -> T.Text -> T.Text
constructQuery city state = "select astronomy, item.condition from weather.forecast" <>
" where woeid in (select woeid from geo.places(1)" <>
" where text=\"" <> city <> "," <> state <> "\")"
buildRequest :: T.Text -> IO ByteString
buildRequest yql = do
let root = "https://query.yahooapis.com/v1/public/yql"
datatable = "store://datatables.org/alltableswithkeys"
opts = defaults & param "q" .~ [yql]
& param "env" .~ [datatable]
& param "format" .~ ["json"]
r <- getWith opts root
return $ r ^. responseBody
run :: T.Text -> IO (Maybe Weather)
run yql = buildRequest yql >>= (\r -> return $ decode r :: IO (Maybe Weather))
-- IP Lookup
getLocation:: IO (Maybe IpResponse)
getLocation = do
r <- get "http://ipinfo.io/json"
let body = r ^. responseBody
return (decode body :: Maybe IpResponse)
-- 组合器
runMyLocation:: IO (Maybe Weather)
runMyLocation = do
r <- getLocation
case r of
Just ip -> getWeather ip
_ -> return Nothing
where getWeather = (run . (uncurry constructQuery) . (city &&& region))
在不使用显式模式匹配“退出”Maybe Monad的情况下,是否可能同时运行getLocation和run线程?
getWeather
的类型,认为它是IpResponse -> Weather
而不是IpResponse :: IO (Maybe Weather)
。我会提供一个澄清的编辑。 - Chris Taylor