In short one may need to mimic creating and running ReaderT subprogram using Tagless Final approach.
Consider this endpoint in some app without TF:
class Endpoints(fooService: FooService, barService: BarService, ...){
def endpoints = HttpRoutes.of[IO] {
case ROOT -> "handle" => for {
body <- req.as[Body]
trace = genTrace
logContext = buildCtx(body)
auth = req.authInfo
result <- handle.run(auth, trace, logContext)
response <- Ok(result)
} yield response
}
def handle(body: Body): ReaderT[IO, (Auth, Trace, LogCtx), Result] = ???
//this method calls multiple other services and methods which also return `ReaderT[IO, ...]`.
//some of them are using context from reader to provide contextual logging or to avoid passing authorization as method parameters
}
And AFAIK there is no way to represent this behavior in tagless final code right now.
So here comes my proposal: cats-mtl should have some typeclass which can represent this, let's call it Run:
In short one may need to mimic creating and running
ReaderT
subprogram using Tagless Final approach.Consider this endpoint in some app without TF:
And AFAIK there is no way to represent this behavior in tagless final code right now.
So here comes my proposal: cats-mtl should have some typeclass which can represent this, let's call it
Run
:it should provide context of type
R
to computationga
of typeG[A]
to evaluate it to another computation of typeF[A]
.So now we can write the endpoint like that:
So what do you think about this proposal? I could try to implement this if it seems like a good idea.