Cats: Proposal: lifting between monad transformers, simple effect types and raw types

Created on 4 Dec 2018  Â·  2Comments  Â·  Source: typelevel/cats

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:

  • There's a redundancy of information: in general, right uniquely implies EitherT when used on F[A]
  • You could solve the above redundancy by importing 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.
  • There are extra parentheses: right[E](fa) vs fa.toRight. Parentheses clutter code.
  • The syntax is not uniform with that of A: if I can do a.pure[EitherT[...]], I'd also like to be able to do fa.toRight[E].

Most helpful comment

why not use asRightT to be similar to asRight for Either syntax

All 2 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LukaJCB picture LukaJCB  Â·  3Comments

tg44 picture tg44  Â·  4Comments

chuwy picture chuwy  Â·  4Comments

durban picture durban  Â·  3Comments

davidabrahams picture davidabrahams  Â·  3Comments