Skip to content
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

Kleisli#andThen unavailable for functor Validated[X, ?] #2013

Closed
andyscott opened this issue Nov 3, 2017 · 2 comments
Closed

Kleisli#andThen unavailable for functor Validated[X, ?] #2013

andyscott opened this issue Nov 3, 2017 · 2 comments

Comments

@andyscott
Copy link
Contributor

andyscott commented Nov 3, 2017

Composing Kleisli's with andThen isn't possible when the functor is Validated[X, ?] even though validated has an andThen method.

This is because Kleisli's andThen is an alias for flatMap and requires a FlatMap instance but Validated doesn't have a FlatMap instance (rightly so).

I don't know if it's reasonable, but there could be an AndThen type class in the same manner as FlatMap. The laws could be the same and for the vast majority of the instances the andThen method would just alias to flatMap. A default internal AndThenIsFlatMap trait could bake this into existing FlatMap instances. I don't know if this has any broader benefit outside of fixing the issue described above.

@johnynek
Copy link
Contributor

johnynek commented Nov 3, 2017

we have the Parallel work #1837 which could be used here. So, when you have a Parallel[F, G] you could do .andThen which lifts the applicative into a monad, flatmaps, then turns it back to the applicative.

@LukaJCB
Copy link
Member

LukaJCB commented Nov 25, 2017

Just to add to this, Kleisli also has a Parallel instance if the F[_] inside has a Parallel instance, so you can use Either for any thing you want to do using andThen and when composing things where you'd typically use Validated, use parMapN or parTraverse or something like that! :)

FWIW, here's an example I just ran in the REPL:

scala> val x = Kleisli((i: Int) => i.asRight[String])
x: cats.data.Kleisli[[+B]Either[String,B],Int,Int] = Kleisli($$Lambda$2585/1074814992@1f9843e5)

scala> val y = Kleisli((i: Int) => i.toDouble.asRight[String])
y: cats.data.Kleisli[[+B]Either[String,B],Int,Double] = Kleisli($$Lambda$2586/357402099@2a90f681)

scala> val z = x andThen y
z: cats.data.Kleisli[[+B]Either[String,B],Int,Double] = Kleisli(cats.data.Kleisli$$Lambda$2589/2011040303@4e1ff808)

scala> val w = Kleisli((d: Double) => if (d < 5.0) d.toString.asLeft[Double] else d.asRight[String])
w: cats.data.Kleisli[[+B]Either[String,B],Double,Double] = Kleisli($$Lambda$2590/1381774303@1dc0c104)

scala> val v = Kleisli((d: Double) => "Error".asLeft[Double])
v: cats.data.Kleisli[[+B]Either[String,B],Double,Double] = Kleisli($$Lambda$2591/1179268926@2206e39a)

scala> z andThen (v, w).parMapN(_ + _)
res4: cats.data.Kleisli[[+B]Either[String,B],Int,Double] = Kleisli(cats.data.Kleisli$$Lambda$2589/2011040303@3e52d414)

scala> res4.run(2)
res5: Either[String,Double] = Left(Error2.0)

scala> res4.run(6)
res6: Either[String,Double] = Left(Error)

@LukaJCB LukaJCB closed this as completed Jul 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants