我应该如何在Haskell中从多个网络请求创建数据结构

时间:2017-10-04 18:04:12

标签: haskell wreq

我是Haskell的新手,所以请提前为这个潜在的愚蠢问题道歉。

我想在我的应用程序中构建一个由两个http请求构建的数据结构。

我的第一个请求获得了一个基本的用户列表,我可以选择decodeMaybe [User]

 r <- getWith opts "https://www.example.com/users"
 let users = decode $ r ^. responseBody :: Maybe [User]

但是如果我想通过为每个响应的用户调用第二个端点来丰富我的用户数据

r2 <- getWth opts "https://www.example.com/users/{userid}/addresses"
let enrichedUser = decode $ r2 ^. responseBody :: Maybe EnrichedUser

我不能把这些部分拼凑在一起。我在do块中,期待IO ()

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

我假设enrichedUser的类型应该是Maybe EnrichedUser而不是Maybe [EnrichedUser],对吗?

如果是这样,从[User]中提取users :: Maybe [User]列表后,您遇到的问题是为每个 {运行monadic操作(以获取网页) {1}}。在User中有一个方便的组合器:

Control.Monad

可以专门针对您的情况:

mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])

这就是说,如果您知道如何编写一个带mapM :: (User -> IO EnrichedUser) -> ([User] -> IO [EnrichedUser]) 的函数并创建一个可以创建User的IO操作,您可以使用EnrichedUser将其转换为获取列表mapM并创建IO操作以创建整个列表[User]的函数。

在你的应用程序中,我认为前一个函数看起来像:

[EnrichedUser]

然后你可以写(在你的IO do-block中):

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 = ...

为简单起见,我在此处省略了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

其他一切都会保持不变。