2

我是 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 ()

任何帮助,将不胜感激!

4

1 回答 1

1

我假设的类型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

其他一切都将保持不变。

于 2017-10-04T21:34:32.530 回答