better-monadic-for
better-monadic-for copied to clipboard
Alternative `flatMap` possible?
Scala's "for comprehensions" first try to use withFilter
and then fallback to filter
if it doesn't exist.
I wonder if in a compiler plugin like this we could do the same thing for flatMap
... try a different a different name first, like flatMapT
or something and if the type doesn't have it, then fallback to flatMap
.
My problem is basically described here: https://contributors.scala-lang.org/t/proposal-for-opaque-type-aliases/2947/139
TL;DR — the flatMap
on EitherT
is:
// Does left widening
def flatMap[AA >: A, D](f: B => EitherT[F, AA, D])(implicit F: Monad[F]): EitherT[F, AA, D]
Which is basically different than the flatMap
we get by implementing cats.FlatMap
:
// No type widening
def flatMap[D](f: B => EitherT[F, A, D])(implicit F: Monad[F]): EitherT[F, A, D]
And if EitherT
has an "opaque type" encoding, then these 2 signatures end up being in conflict and an explicit import cats.implicits._
will mask the first definition.
And giving that function a different name isn't a problem, we've got IDEs that help with the auto-completion, but in such a case the problem will be the for comprehensions, which in FP heavy code are ubiquitous.
@alexandru Scala doesn't fallback to filter
anymore:
I guess you could try to do what the PR did in reverse, kind of, but I'm actually not familiar with that machinery at all.
Alternatively, you can ditch cats.implicits._
in your project and have your own syntax object:
object appImplicits extends cats.syntax.AllSyntax /* with a ton of other traits */ {
implicit def opsForEitherT[F, E, A](self: MyEitherT[F, E, A]): MyEitherT.Ops[F, E, A] = ???
}
this should work because your ops will take priority over inherited cats' ones.