-
Notifications
You must be signed in to change notification settings - Fork 786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cats-mtl #4758
base: main
Are you sure you want to change the base?
cats-mtl #4758
Conversation
apply(httpRoutes) | ||
|
||
def httpApp[F[_]: Applicative](httpApp: HttpApp[F]): HttpApp[F] = | ||
def httpApp[F[_]](httpApp: HttpApp[F])(implicit F: Monad[F]): HttpApp[F] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you strengthen this constraint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because apply
needs a Monad
now, and Kleisli
doesn't have one unless F
has one.
There are several examples here. I did cowardly hide from a couple of the more difficult ones. I think it's enough to decide whether we want to proceed with this and try to attract new contributors, or stick with what we have. |
It doesn't make much sense to release half the middlewares in this style. Unless someone has a good reason otherwise, I think this can slip to 1.0. |
I think this proves the techinque, and we could recruit help to get the rest done. |
Much cleaner! Is the plan still to do this for 1.0? I'm happy to lend a hand if so. |
I'm still in favor of this and regret that we didn't finish before 0.23. I would love the help! How about I reserve the merge conflicts and get this approved to ensure we're not the only two who like it, and then I can hand it off to you? |
Sure, with the caveat that I don't take on any feeling of responsibility or obligation 😉 How about merging this once approved, opening an issue, and merging new ones as they're ready? That way we avoid new merge conflicts. |
Agreed. I got a bit carried away implmenting them while proving to myself it was good, and then gathering support for the idea. One-by-one would be much better moving forward. |
I haven't read through the whole PR history so perhaps I missed it, but what is the goal of these changes? I'm very concerned with the kind of type signatures appearing in the diff here. Currently in my experience, http4s has consistently been the single library worst for new-to-scala people or new-to-fp people, of libraries that are in common use across the tech stack. I'm afraid that this change would reduce the accessibility even more. I love using the library because it has a ton of nice properties, but this feels like a complexity increase that I'm not sure is fully justified. It could make me reluctant to continue recommending it to scala teams that aren't already waist-deep in FP scala |
@Daenyth can you elaborate on that more? To me this mostly looks like the effects of this are changing functions which were formerly explicitly Are you worried just the presence of the new constraints will be confusing? |
Said this on Discord but it's better to keep the discussion here: I think a big motivating goal for these changes is that whilst final tagless is harder to work with than concrete IO, (the assumption is that) the reverse is true for Kleisli, which is relevant when writing middlewareswhere the Kleisli-ness cannot be otherwise ignored. |
Kleisli continues to be controversial. MTL works both for Kleisli or for more HTTP-specific constructions. A better discussion is at #4846. |
On the topic of difficult-to-parse type signatures, one thing that might help is to use more meaningful names for type parameters - for example the constructor for def apply[F[_], G[_], B](fb: F[B])(implicit
F: Monad[F],
FMK: MonoidK[F],
L: Local[F, Request[G]]
): F[B] to the following, which is much more self-explanatory: def apply[Rt[_], F[_], Resp](fb: Rt[Resp])(implicit
Rt: Monad[Rt],
RtMK: MonoidK[Rt],
L: Local[Rt, Request[F]]
): Rt[Resp] |
What is |
Yep, wanted something more meaningful than |
What's the next step on this, just pull the chances out into individual PRs that can be merged one by one? |
I think splitting it up is the way, but before we invest more in it:
|
I have a question about this. I'm curious about the choice between using |
I guess I'm confused if we why if we really need both |
I don't think I understand this - can you give an example of what the signature would look like? |
Lol, seems I was stumbling over my ifs and whys there 😅 For example, in feral we have the general shape trait LambdaEnv[F[_], Event] { outer =>
def event: F[Event]
def context: F[Context[F]]
final def mapK[G[_]: Functor](f: F ~> G): LambdaEnv[G, Event] =
new LambdaEnv[G, Event] {
def event = f(outer.event)
def context = f(outer.context).map(_.mapK(f))
}
} |
Ok, so I played out my idea a bit. My hope was that something like //> using scala "2.13.8"
//> using plugin "org.typelevel:::kind-projector:0.13.2"
//> using lib "org.http4s::http4s-core::1.0.0-M32"
//> using lib "org.typelevel::cats-mtl::1.2.0"
import cats._
import cats.data._
import cats.mtl._
import cats.syntax.all._
import org.http4s._
trait AskRequest[F[_]] extends Ask[F, Request[F]]
trait LocalRequest[F[_]] extends AskRequest[F] with Local[F, Request[F]]
object AskRequest {
implicit def forKleisli[F[_]](implicit F: Monad[F]): LocalRequest[Kleisli[F, Request[F], *]] =
new LocalRequest[Kleisli[F, Request[F], *]] {
private type G[A] = Kleisli[F, Request[F], A]
def applicative = Applicative[Kleisli[F, Request[F], *]]
def ask[E2 >: Request[Kleisli[F, Request[F], *]]]: Kleisli[F, Request[F], E2] =
Kleisli.ask[F, Request[F]].map(_.mapK(Kleisli.liftK[F, Request[F]])).widen
def local[A](fa: Kleisli[F, Request[F], A])(
f: Request[Kleisli[F, Request[F], *]] => Request[Kleisli[F, Request[F], *]]
): Kleisli[F, Request[F], A] =
???
}
} |
Are there performance implications for this? Or will JIT make it all go away as they're all monomorphic callsites (I think)? |
That is a great question that I have not measured to adequately answer. Will also be hard to benchmark, because whatever impact we see isolating it may not matter in the scope of an application dressed in full TCP socket regalia. |
A cleaner version of #4754 now that I have a better idea what I'm doing.