Skip to content

Instantly share code, notes, and snippets.

@armanbilge
Created February 25, 2022 06:09
Show Gist options
  • Save armanbilge/3a2622d2d3834fe8c487ad74f2eb957a to your computer and use it in GitHub Desktop.
Save armanbilge/3a2622d2d3834fe8c487ad74f2eb957a to your computer and use it in GitHub Desktop.
//> 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