typelevel / cats

Lightweight, modular, and extensible library for functional programming.
https://typelevel.org/cats/
Other
5.2k stars 1.19k forks source link

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

Open anatoliykmetyuk opened 5 years ago

anatoliykmetyuk commented 5 years ago

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:

kailuowang commented 5 years ago

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.

julien-truffaut commented 5 years ago

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

henryxparker commented 2 years ago

liftEitherT and liftOptionT were added to typelevel/mouse in this PR. F[A].toRight[L]: EitherT[F, L, A] and F[A].toLeft[R]: EitherT[F, A, R] were considered but ultimately pulled from the PR since concerns were raised that it wasn't common enough of a use case to justify increasing compile time/ide responsiveness.