Right now we're using two type parameters which essentially means bidirectional functional dependencies. However all of our functions making use of parallel are uniquely determined by F, meaning we can make G an abstract type parameter which would get rid of the some of boilerplate when writing abstract code over Parallel. This is a breaking change, so would need to go to cats 2.0. :)
I've created a temporary lib to deliver this feature until we can get this for 2.0.
Let me know if anything would like to be tweaked or to initiate a PR upstream to cats. Everything is working for me so I'm inclined to release a 0.1.0
Not trying to be annoying but I'd like to point out that I did mention the risk of releasing something in as stable before it's battle tested. https://github.com/typelevel/cats/pull/1837#issuecomment-333116634
If we chose to roll this one out in a more gradual way ( e.g. released in an experiment module first) we might avoided this problem. Of course, there would be other trade-offs.
Another idea here is a Sequential[A[_]] type class which would be the dual of a Parallel[M[_]]
So, if you have an applicative, but you want to go sequential for a bit (I am using Validated, but here I need andThen) you take the Sequential[ValidatedNec[String, ?]] and then it can allow you to work with Either for bit and convert back to ValidatedNec at the end.
one work around I did internally was just make Parallel1 very similar to @ChristopherDavenport 's example.
We could do that in cats core. 1 meaning 1 type parameter...
It's a bit of an ugly name but it makes it much more convenient to use and we don't need to wait until cats 3.0.
I think we have to accept warts if we want binary compatibility (which I do).
So just duplicate it all into Parallel1 for now, and then at some point deprecate Parallel? Might be a good solution
Well my solution was to resolve Parallel using Parallel1 so Parallel1 is a wrapper for Parallel only used to ease implicit resolution.
Otherwise existing instances of Parallel wouldn鈥檛 be usable.
Here is what I added:
import cats.Parallel
sealed trait Parallel1[F[_]] extends Serializable {
type A[_] // applicative type
implicit def parallel: Parallel[F, A]
}
object Parallel1 {
type Aux[F[_], A0[_]] = Parallel1[F] { type A[x] = A0[x] }
implicit def parallel1Instance[F[_], A0[_]](implicit p: Parallel[F, A0]): Parallel1.Aux[F, A0] =
new Parallel1[F] {
type A[x] = A0[x]
val parallel = p
}
implicit def parallelFromParallel1[F[_]](implicit p: Parallel1[F]): Parallel[F, p.A] =
p.parallel
}
Then you can use it with:
import Parallel1.parallelFromParallel1
def sequence[F: Parallel1, A](as: List[F[A]]): F[List[A]] =
Parallel.parSequence(as)
We could probably also make parallelFromParallel1 a low priority on the Parallel object and not even have the import.
Why not use Par and then existing users on cats-par can just migrate via changing imports?
It sounds a lot like you have spent time to recreate the work that has been built out incrementally in cats-par.
No offense Chris, but this is 27 lines of code in total. It was less work that updating our builds to depend on a third party we would have to keep up to date with changes to cats/etc...
And as you note in your readme, I was the one that suggested this approach originally.
I totally was suggesting bringing it in. Not depending on the library.
Edit: I see that was about your company approach rather than cats. What I was suggesting is that if we are going to bring in a slightly altered name into cats, that doing so in a way that allows those on the third-party lib to transition would be a smooth way to upgrade.
@ChristopherDavenport a mere rename is how I read your intention as well.
I think I like Parallel1 siightly better, because it looks supplementary to Parallel, while it's harder to tell the difference between Par and Parallel. For cats-par users, they can do a replace
import cats.temp.par._ to import cats.{Parallel1 => Par}, not much extra cost to them.
a global replacement of Par to Parallel1 shouldn't be terrible either.
Update: My replace example might be off, but you get the idea, a replacement to add a name alias shouldn't be too much more costly than removing the import right?
@LukaJCB so how about we create a new issue with @johnynek 's solution and label it with "help wanted"?
Most helpful comment
I've created a temporary lib to deliver this feature until we can get this for 2.0.
Let me know if anything would like to be tweaked or to initiate a PR upstream to cats. Everything is working for me so I'm inclined to release a
0.1.0https://github.com/ChristopherDavenport/cats-par