我应该如何从 Haskell 中的多个网络请求创建数据结构
How should I create a data structure from multiple network requests in Haskell
我是 Haskell 的新手,所以对于这个可能很愚蠢的问题提前表示歉意。
我想在我的应用程序中构建一个由两个 http 请求构建的数据结构。
我的第一个请求获得了一个基本的用户列表,我可以选择 decode
到 Maybe [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 ()
如有任何帮助,我们将不胜感激!
我假设 enrichedUser
的类型应该是 Maybe EnrichedUser
而不是 Maybe [EnrichedUser]
,对吗?
如果是这样,在从 users :: Maybe [User]
中提取 [User]
列表后,您面临的问题是 运行 [=47] 的单子操作(获取网页) =]每个User
。在 Control.Monad
:
中有一个方便的组合器
mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])
可以根据您的情况专门针对:
mapM :: (User -> IO EnrichedUser) -> ([User] -> IO [EnrichedUser])
这就是说,如果您知道如何编写一个接受 User
的函数并创建一个将创建 EnrichedUser
的 IO 操作,您可以使用 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 块中):
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
其他一切都将保持不变。
我是 Haskell 的新手,所以对于这个可能很愚蠢的问题提前表示歉意。
我想在我的应用程序中构建一个由两个 http 请求构建的数据结构。
我的第一个请求获得了一个基本的用户列表,我可以选择 decode
到 Maybe [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 ()
如有任何帮助,我们将不胜感激!
我假设 enrichedUser
的类型应该是 Maybe EnrichedUser
而不是 Maybe [EnrichedUser]
,对吗?
如果是这样,在从 users :: Maybe [User]
中提取 [User]
列表后,您面临的问题是 运行 [=47] 的单子操作(获取网页) =]每个User
。在 Control.Monad
:
mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])
可以根据您的情况专门针对:
mapM :: (User -> IO EnrichedUser) -> ([User] -> IO [EnrichedUser])
这就是说,如果您知道如何编写一个接受 User
的函数并创建一个将创建 EnrichedUser
的 IO 操作,您可以使用 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 块中):
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
其他一切都将保持不变。