我有以下代码从分页 API 端点获取两页数据。我想修改query
函数以继续获取页面,直到它找不到更多数据(因此take 2
在下面的代码中替换为查看 API 响应的内容)。
我的问题是是否可以在不将query
功能更改为功能的情况下实现这一目标IO
。如果是这样,我将如何去做。如果没有,有没有办法在不编写递归函数的情况下做到这一点?
这是代码:
#!/usr/bin/env stack
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import Servant.Client
import Network.HTTP.Client (newManager, defaultManagerSettings)
import Data.Proxy
import Servant.API
import Data.Aeson
import GHC.Generics
-- data type
data BlogPost = BlogPost
{ id :: Integer
, title :: String
} deriving (Show, Generic)
instance FromJSON BlogPost
-- api client
type API = "posts" :> QueryParam "_page" Integer :> Get '[JSON] [BlogPost]
api :: Proxy API
api = Proxy
posts :: Maybe Integer -> ClientM [BlogPost]
posts = client api
-- query by page
query :: ClientM [[BlogPost]]
query = sequence $ take 2 $ map posts pages
where
pages = [Just p | p <- [1..]]
-- main
main :: IO ()
main = do
manager' <- newManager defaultManagerSettings
let url = ClientEnv manager' (BaseUrl Http "jsonplaceholder.typicode.com" 80 "")
posts' <- runClientM query url
print posts'
我试图用它takeWhileM
来做到这一点,最终使查询成为一个IO
函数并传递url
给它。它开始看起来很糟糕,我无法匹配类型(我觉得我需要更像(a -> m Bool) -> m [a] -> m [a]
而不是(a -> m Bool) -> [a] -> m [a]
什么东西takeWhileM
- 仍然觉得这很奇怪,因为我将此功能视为过滤器,但输入list 和 output list 是不同的(一个有 monad,另一个没有)。