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

Integration with cats Parallel #969

Closed
SystemFw opened this issue Nov 6, 2017 · 8 comments
Closed

Integration with cats Parallel #969

SystemFw opened this issue Nov 6, 2017 · 8 comments

Comments

@SystemFw
Copy link
Collaborator

SystemFw commented Nov 6, 2017

cats has recently added a Parallel typeclass which relates types such as Either and Validation, and lets you do (fa, fb).parMap(foo), which will use the "related" Applicative, while keeping consistent <*> and flatMap, and without requiring any explicit tagging by the user.
This gives us an opportunity to provide an Applicative Api in addition to start for parallel F (I like start so I want to keep it regardless). Should we:

  • Do nothing
  • Add a Parallel instance for any F[_]: Effect. This will be an orphan so perhaps unadvisable, but it will mean we can remove parSequence and parTraverse (already defined for every Parallel)
  • Add a ParIO newtype, and add a Parallel[IO, ParIO] instance

More info on Parallel: typelevel/cats#1837

@mpilquist
Copy link
Member

👍

I like the idea of a parallel instance for any effect. Is there a way we could do this as a newtype so as to avoid the orphan?

@SystemFw
Copy link
Collaborator Author

SystemFw commented Nov 6, 2017 via email

@mpilquist
Copy link
Member

mpilquist commented Nov 6, 2017

Why can't we do something like:

case class Par[F[_],A](value: F[A])
object Par {
  implicit def parallelInstanceForEffect[F[_]](implicit F: Effect[F]): Parallel[F, Par[F,?]] = new Parallel[F,Par[F,?]] {
    def applicative: Applicative[Par[F,?]] = Par.applicativeInstance
    def monad: Monad[F] = F
  }
  def applicativeInstance[F[_]](implicit F: Effect[F]): Applicative[F] = ...
}

@SystemFw
Copy link
Collaborator Author

SystemFw commented Nov 6, 2017

I'm actually thinking we will have the same problem regardless of whether we do it for IO or for F (and therefore we should prefer a solution like the one you propose), namely that we would need an import or a type annotation to make the syntax work:
(ioA, ioB).parMap((x,y) => ...)
parMap would need an instance for Parallel[F, Par[F, ?]], which will only be in scope if we put it in the companion object of F (and let the "functional dependency" trigger), or if we specify parMap[IO, ParIO]((x,y) => ) or if we bring it into scope with an import.
However I haven't written any code to try, so I might well be wrong.

@SystemFw
Copy link
Collaborator Author

SystemFw commented Nov 6, 2017

I think the only way to avoid an orphan (or in any case something that would require an import to be usable) would be to newtype IO, not ParIO...which I'm definitely not sure it's a good idea. But once more, I'll need to spend some time on this

@mpilquist
Copy link
Member

Right, gotcha.

@LukaJCB
Copy link
Member

LukaJCB commented Nov 6, 2017

You're right sadly, Scala can't figure out the M if the parallel instance is defined on the companion of F(I've tried this in the past), so there will have to be an import :/
In that case I think it makes sense to provide it for any Effect.

@SystemFw
Copy link
Collaborator Author

SystemFw commented Nov 7, 2017

Another approach would be typelevel/cats-effect#83

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