In practice, I often encounter situations when I need to lift F[_] to EitherT or OptionT. For EitherT, the only current option is EitherT.right[E](foo: F[A]): EitherT[F, E, A]. Compare that to A-F[A] interop or OptionT-EitherT interop:
(a: A).pure[F]: F[A]
(o: OptionT[F, A]).toRight(error: E): EitherT[F, E, A]
(e: EitherT[F, E, A]).toOption: OptionT[F, A]
Similarly, I think it is a good idea to have rich wrappers such as to allow:
(fa: F[A]).toRight[E]: EitherT[F, E, A]
(fa: F[A]).toLeft[B]: EitherT[F, A, B]
(fe: F[Either[E, A]]).lift: EitherT[F, E, A]
(fo: F[Option[A]]).lift: OptionT[F, A]
The EitherT.right(foo: F[A]) is a bit cumbersome because:
right uniquely implies EitherT when used on F[A]EitherT.{right, ...} – however, there is a bunch of conversion methods defined on EitherT, and the need to manage the imports might introduce some mental overhead. Ideally, I'd like to be able to just import Cats once (e.g. currently I am using import cats._, cats.implicits._, cats.data._, cats.effect._) and forget about it.right[E](fa) vs fa.toRight. Parentheses clutter code.A: if I can do a.pure[EitherT[...]], I'd also like to be able to do fa.toRight[E].I agree EitherT.right(foo: F[A]) is a bit of typing, on the other hand, I think there is a reason we might want to stick with it.
(fa: F[A]).toRight[E]: EitherT[F, E, A] will be ambiguous to read with the existing a.asRight[E]: Either[A, E], so if we want to add this method the name has to be something like asEitherTRight to avoid the ambiguity. And if you do that, fa.asEitherTRight is exactly the same num of characters as EitherT.right(fa). Adding an extension method to any F[A] is a cost, and in this particular case, I am not sure if the benefit outweighs it.
On a side note, I am on the camp of abstracting any effect type F[_] as much as possible. There shouldn't be much code directly dealing with concrete effect types like EitherT and OptionT. Instead, most of the class/methods are declared as class MyClass[F[_]: MonadError[E, ?]]. If you take this approach, then mostly likely you just need to define a FunctionK from one concrete F[_] to another F[_] once per application. Then, among other benefits, there is less need for this kind of conversion methods.
why not use asRightT to be similar to asRight for Either syntax
Most helpful comment
why not use
asRightTto be similar toasRightforEithersyntax