add Local[F, Span[F]] instance where F is Kleisli[F, Span[F], *] - #713
Conversation
|
Hmm, is the problem here? I.e. should that be asking for a Edit: even better, the We'll have to add a (low-priority?) instance for |
|
Hmm, in principle I like that, but I'm not sure it solves my problem. If I'm understanding you correctly, I was able to implement implicit def natchezMtlTraceViaLocal[F[_], G[_]](implicit ev: Local[F, Span[G]],
fk: MonadPartialOrder[G, F],
F: MonadCancelThrow[F],
G: MonadCancelThrow[G],
): Trace[F]and then use it by changing the launch point of my program from def foo[F[_] : MonadCancelThrow](implicit L: Local[F, Span[F]]): F[Unit]to def foo[F[_] : MonadCancelThrow, G[_] : MonadCancelThrow](implicit L: Local[F, Span[G]],
fk: MonadPartialOrder[G, F]): F[Unit]and then call it with one of foo[Kleisli[IO, Span[IO], *], IO]
foo[IO, IO]instead of one of foo[Kleisli[IO, Span[IO], *]]
foo[IO]which is obviously not as pleasant to use. Am I missing something? |
|
Thanks for trying that! Maybe we can use the partially-applied trick here? So that you only need to specify one of the type parameters. |
|
Or a bespoke encoding. trait LocalSpanAndMonadPartialOrderAndMonadCancelThrow[F[_]] {
type G[_]
def localSpan: Local[F, Span[G]]
def monadPartialOrder: MonadPartialOrder[G, F]
def monadCancelThrow: MonadCancelThrow[G]
}
object LocalSpanAndMonadPartialOrderAndMonadCancelThrow {
type Aux[F[_], G0[_]] = LocalSpanAndMonadPartialOrderAndMonadCancelThrow[F] { type G = G0 }
implicit def instance[F[_], G0[_]](
implicit ls: Local[F, Span[G0]],
mpo: MonadPartialOrder[G0, F]
mct: MonadCancelThrow[G0]
): Aux[F, G0] = new LocalSpanAndMonadPartialOrderAndMonadCancelThrow[F] {
type G = G0
def localSpan: Local[F, Span[G]] = ls
def monadPartialOrder: MonadPartialOrder[G, F] = mpo
def monadCancelThrow: MonadCancelThrow[G] = mct
}
}
implicit def natchezMtlTraceViaLocal[F[_]](
implicit ev: LocalSpanAndMonadPartialOrderAndMonadCancelThrow[F],
F: MonadCancelThrow[F],
): Trace[F] = ??? |
…ram[F[_]: MonadCancelThrow](implicit L: Local[F, Span[F]]): F[Unit]`
|
I think I got that working on Scala 2.13 and 3, but I haven't been able to get it to infer on 2.12. I also had to change the app code method definition to def foo[F[_]: LocalSpanAndMonadPartialOrderAndMonadCancelThrow : MonadCancelThrow]: F[Unit]which still doesn't feel ideal since it's a new thing that would have to be explained and understood. I added a |
|
Hm I see 🤔 in that case, I wonder if the partially-applied trick would be better. I think this boils down to:
Pick 2. Suffice to say, I see the merits of your original proposal 😅 Still, I think the implementation should be in terms of |
…rio being contemplated
…i[F, Span[F], *]]
|
Maybe I've been looking at this too long and I'm just missing something, but I updated the implementation to use (I did take it a lot farther on another branch, introducing a new thing I called |
Oh crap, no I think it's just me 😬 as soon as you mentioned I previously learned this in #448, but seems I forgot 🤦 So sorry for the wild goose chase, thanks for trying all my suggestions 😕 |
|
No worries! Given that, do you still think the changes in dcf71de (that introduced |
Let me revise this (and hopefully get it right this time :) — the implementation should be in terms of To be more concrete, can we implement this roughly signature? def natchezMtlTraceForLocal[F[_], G[_]](implicit
local: Local[F, Span[G]],
F: MonadCancel[F, _],
lift: G ~> F,
lower: F ~> G
): Trace[F] = ???and then we just do something like this? implicit def localSpanForKleisli[F[_]: MonadCancel] = natchezMtlTraceForLocal[Klesli, F]and another one for the case where |
|
I think that signature maybe misses the point of this PR? This is meant to handle the situation where I have a method def doSomethingInNewRoot[F[_]](entryPoint: EntryPoint[F])(implicit L: Local[F, Span[F]])and I want to call it with In this situation, I don't need a |
Gah 🤦 yes it does. I'm ... going to shut my mouth now 😅 the call site is |
When fulfilling a effect-polymorphic function demanding an implicit
Local[F, Span[F]]with[F[_], A] =>> Kleisli[F, Span[F], A], the implicit instances provided by cats-mtl don't quite fit. The code demandsbut
Local.baseLocalForKleislireturns(i.e., the
Eparameter is wrong), andLocal.localForKleislirequires an implicitwhich we don't have.
AFAICT, it's safe to (effectively)
imaptheLocal[Kleisli[F, Span[F], *], Span[F]]returned byLocal.baseLocalForKleisliusingKleisli.liftKandKleisli.applyK.Kleisli.liftKwill turnSpan[F]intoSpan[Kleisli[F, Span[F], *]], which, when run, will ignore anySpan[F]s passed to eachKleisli[F, Span[F], *]. We take advantage of that by immediatelymapKing it back toSpan[F], applying a no-op span that we know will never actually be used.(Alternatively, if there's a better way to do this, let me know and I'll change this PR to document that method instead.)