protocol HasDatabase { func database: Database }
protocol HasHttpClient { func httpClient: HttpClient }
func fetchAndSave<M: MonadReader>(userId: Int)-> M.M<()>
where M.Env = HasDatabase & HasHttpClient {
#monadic {
api <- M.ask().map { $0.httpClient }
db <- M.ask().map { $0.database }
user <- api.fetch(userId: userId)
db.save(user: user)
}
}
Explanation:
// #monadic is a freestanding macro, with the addition of generic associated
// types, this macro should be possible to make with no additional language
// changes. It just converts it into a chain of flatMap calls,
// this being equivalent to the above:
func fetchAndSave<M: MonadReader>(userId: Int)-> M.M<()>
where M.Env = HasDatabase & HasHttpClient {
M.ask().map { $0.httpClient }.flatMap { api in
M.ask().map { $0.database }.flatMap { db in
api.fetch(userId: userId).flatMap { user in
db.save(user: user)
}
}
}
}