Вы пробовали unfoldM
?
unfoldM :: Monad m => m (Maybe a) -> m [a]
Давайте обновим posts
таким образом
posts :: Maybe Integer -> ClientM (Maybe [BlogPost])
posts = fmap notNil . client api where
notNil [] = Nothing
notNil bs = Just bs
Идея состоит в том, чтобы обновить query
, чтобы вы могли просто использовать unfoldM query
и получить обратно ClientM [[BlogPost]]
. Для этого тип query
должен быть
query :: ClientM (Maybe [BlogPost])
означает, что номер страницы должен исходить из среды:
query = forever $ page >>= posts
Очевидно, что здесь происходит некоторая форма состояния, поскольку нам нужен способ отслеживать номер текущей страницы. Мы можем заключить действие клиента в StateT
:
type ClientSM = StateT Integer ClientM
page :: ClientSM Integer
page = get <* modify (+1)
Это действие требует нескольких дополнительных изменений как query
, так и posts
. Редактировать: см. Ниже, чтобы узнать, как я проник в автобус. Сначала нам нужно отменить действие клиента в монаде состояния:
posts :: Integer -> ClientSM (Maybe [BlogPost])
posts = fmap notNil . lift . client api . Just where
notNil [] = Nothing
notNil xs = Just xs
Необходимо изменить только тип query
query :: ClientSM (Maybe [BlogPost])
Наконец, главное действие просто необходимо очистить стек монады и развернуть запрос:
main = do
manager' <- newManager defaultManagerSettings
let url = mkClientEnv manager' (BaseUrl Http "jsonplaceholder.typicode.com" 80 "")
result <- flip runClientM url $ flip runStateT 1 $ unfoldM query
case result of
Left error -> print error
Right (posts, _) -> print posts
Я не проверял это, но он компилируется 10
posts
не обращает внимания на состояние и должен оставаться таковым. Итак, не меняя мою оригинальную версию выше, вам просто нужно поднять в query
:
query :: ClientSM (Maybe [BlogPost])
query = forever $ page >>= lift . posts . Just