I'm assuming that the type of enrichedUser
is supposed to be Maybe EnrichedUser
and not Maybe [EnrichedUser]
, right?
If so, after extracting the [User]
list from users :: Maybe [User]
, the problem you're facing is running a monadic action (to fetch the web page) for each User
. There's a handy combinator for this in Control.Monad
:
mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])
which can be specialized in your situation to:
mapM :: (User -> IO EnrichedUser) -> ([User] -> IO [EnrichedUser])
This says, if you know how to write a function that takes a User
and creates an IO action that will create an EnrichedUser
, you can use mapM
to turn this into a function that takes a list [User]
and creates an IO action to create a whole list [EnrichedUser]
.
In your application, I imagine the former function would look something like:
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 = ...
and then you can write (in your 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...
I've omitted the Maybe
processing here for simplicity. If enriching fails, you probably want to somehow coerce a regular User
into a default EnrichedUser
anyway, so you'd modify the bottom of the enrich
function to read:
let enrichedUser = case decode $ r2 ^. responseBody of
Nothing -> defaultEnrichment u
Just e -> e
return enrichedUser
and everything else would stay the same.