Created
February 25, 2022 06:09
-
-
Save armanbilge/3a2622d2d3834fe8c487ad74f2eb957a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//> using scala "3.1.1" | |
//> using option "-Ykind-projector" | |
//> using lib "org.tpolecat::natchez-core::0.1.6" | |
import cats._ | |
import cats.data._ | |
import cats.effect.kernel._ | |
import natchez._ | |
// A rough approximation of Resource as a typeclass | |
trait ResourceLike[F[_], G[_]] extends Monad[F] { | |
def make[A](acquire: G[A])(release: A => G[Unit]): F[A] | |
def eval[A](ga: G[A]): F[A] | |
def use[A, B](fa: F[A])(f: A => G[B]): G[B] | |
} | |
// I think this is the downgradeTrace I was actually imagining | |
def downgradeTrace[F[_], G[_]](T: Trace[F], R: ResourceLike[F, G], G: Monad[G]): Trace[G] = | |
new Trace[G] { | |
def span[A](name: String)(ga: G[A]): G[A] = | |
R.use(T.span(name)(R.eval(ga)))(G.pure(_)) | |
def kernel: G[Kernel] = | |
R.use(T.kernel)(G.pure(_)) | |
def put(fields: (String, natchez.TraceValue)*): G[Unit] = | |
R.use(T.put(fields: _*))(G.pure(_)) | |
def traceId: G[Option[String]] = | |
R.use(T.traceId)(G.pure(_)) | |
def traceUri: G[Option[java.net.URI]] = | |
R.use(T.traceUri)(G.pure(_)) | |
} | |
// now, we simultaneously implement both `Trace` and `ResourceLike` for a common effect | |
type TF[F[_], A] = Kleisli[F, Span[F], A] // TF for traceable-F | |
type TR[F[_], A] = Kleisli[Resource[F, *], Span[F], A] // TR for traceable-resource | |
given [F[_]](using F: MonadCancelThrow[F]): ResourceLike[TR[F, *], TF[F, *]] | |
with Trace[TR[F, *]] | |
with StackSafeMonad[TR[F, *]] | |
with { | |
def pure[A](x: A): TR[F, A] = | |
Kleisli.pure(x) | |
def flatMap[A, B](fa: TR[F, A])(f: A => TR[F, B]): TR[F, B] = | |
fa.flatMap(f) | |
def eval[A](ga: TF[F, A]): TR[F, A] = | |
Kleisli(span => Resource.eval(ga.run(span))) | |
def make[A](acquire: TF[F, A])(release: A => TF[F, Unit]): TR[F, A] = | |
Kleisli(span => Resource.make(acquire.run(span))(release(_).run(span))) | |
def use[A, B](fa: TR[F, A])(f: A => TF[F, B]): TF[F, B] = | |
fa.flatMap(f(_).mapF(Resource.eval(_))).mapF(_.use(F.pure(_))) | |
def kernel: TR[F, natchez.Kernel] = | |
Kleisli(span => Resource.eval(span.kernel)) | |
def put(fields: (String, natchez.TraceValue)*): TR[F, Unit] = | |
Kleisli(span => Resource.eval(span.put(fields: _*))) | |
def span[A](name: String)(k: TR[F, A]): TR[F, A] = | |
Kleisli { parent => | |
parent.span(name).flatMap(child => k.run(child)) | |
} | |
def traceId: TR[F, Option[String]] = | |
Kleisli(span => Resource.eval(span.traceId)) | |
def traceUri: TR[F, Option[java.net.URI]] = | |
Kleisli(span => Resource.eval(span.traceUri)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment