我假设的类型enrichedUser
应该是Maybe EnrichedUser
而不是Maybe [EnrichedUser]
,对吧?
如果是这样,在从中提取[User]
列表后users :: Maybe [User]
,您面临的问题是为每个 User
. 有一个方便的组合器Control.Monad
:
mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])
这可以专门针对您的情况:
mapM :: (User -> IO EnrichedUser) -> ([User] -> IO [EnrichedUser])
这就是说,如果您知道如何编写一个接受 aUser
并创建一个将创建一个 IO 操作的函数EnrichedUser
,您可以使用它mapM
来将其转换为一个接受一个列表[User]
并创建一个 IO 操作以创建整个列表的函数[EnrichedUser]
。
在您的应用程序中,我想前一个函数看起来像:
enrich :: User -> IO EnrichedUser
enrich u = do
let opts = ...
let url = "https://www.example.com/users/"
++ userToUserID u ++ "/addresses"
r2 <- getWith opts url
let Just enrichedUser = decode $ r2 ^. responseBody
return enrichedUser
where decode = ...
然后你可以写(在你的 IO do-block 中):
r <- getWith opts "https://www.example.com/users"
let Just users = decode $ r ^. responseBody
enrichedUsers <- mapM enrich users
-- here, enrichedUsers :: [EnrichedUser]
...etc...
为简单起见,我在Maybe
这里省略了处理。如果丰富失败,您可能希望以某种方式强制将常规User
转换为默认值EnrichedUser
,因此您将修改enrich
函数的底部以读取:
let enrichedUser = case decode $ r2 ^. responseBody of
Nothing -> defaultEnrichment u
Just e -> e
return enrichedUser
其他一切都将保持不变。