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

Should there be an IO Monad? #1224

Closed
rongcuid opened this issue Jul 23, 2016 · 8 comments
Closed

Should there be an IO Monad? #1224

rongcuid opened this issue Jul 23, 2016 · 8 comments

Comments

@rongcuid
Copy link

I noticed that Cats does not have an IO monad, while Scalaz does. Is there a reason not to include it in the current implementation? Or is it just "unimplemented"?

@adelbertc
Copy link
Contributor

I believe the omission of an IO or Task monad in Cats is on purpose. I've tried to list the reasons below:

  1. There can only be one IO monad since it sits "at the bottom" and it is sketchy to interpret from one IO/Task monad to another due to execution semantics. That being said, between libraries like FS2 and Monix which provide their own IO/Task-y monads, it is perhaps not desirable to add another one into the mix.
  2. It is not entirely straightforward if we should have a pure IO monad, or an IO monad that also captures async like Task does. Historically folks have gone for the latter, but this introduces complications as Cats wishes to support both the JVM and Scala.JS. Due to differences in the runtimes it is not easy to support both in this particular domain.

@rongcuid
Copy link
Author

Does it have something like an IO monad, then? Or is it just not a common pardigm used in Scala?

If so, what is used to explicitly "mark" impure functions (although I know Scala is an impure language)?

@yilinwei
Copy link
Contributor

@CarlDong

If I want what @adelbertc calls a pure IO Monad I simply alias a type IO = Reader[World, A] where World has the subset of features which delegates to a suitable library such as java nio. This is (usually) sufficient to mark effects.

@adelbertc
Copy link
Contributor

@CarlDong If stack safety is not a concern a plain encoding can be used:

sealed abstract class IO[A] {
  def unsafePerformIO(): A

  def flatMap[B](f: A => IO[B]): IO[B] = f(unsafePerformIO())

  def map[B](f: A => B): IO[B] =flatMap(a => IO.pure(f(a)))
}

object IO {
  def apply[A](a: => A): IO[A] = new IO[A] { def unsafePerformIO(): A = a }

  def pure[A](a: A): IO[A] = new IO[A] { def unsafePerformIO(): A = a }
}

Short of that, for now you'll have to use something from an existing lib like FS2's Task or Doobie's IOLite: https://github.com/tpolecat/doobie/blob/series/0.3.x/yax/core/src/main/scala/doobie/util/iolite.scala

@rongcuid
Copy link
Author

I am more used to Haskell programming so I guess stack safety is pretty important... I will try, though.

@ceedubs
Copy link
Contributor

ceedubs commented Jul 25, 2016

FYI I've created #1227 to add a note about IO/Task (or the lack thereof) to the FAQ.

@adelbertc
Copy link
Contributor

@CarlDong If you're going to end up using streams, then bringing in something like scalaz-stream (aka FS2) (or Monix) is probably the way to go. If you also end up doing some database or HTTP work, there's also libraries like Doobie and HTTP4S that have bindings to scalaz-stream.

@ceedubs
Copy link
Contributor

ceedubs commented Jul 27, 2016

I'm going to go ahead and close this out since there's now an item in the FAQ for this. Thanks for reminding me that it should be added @CarlDong.

@ceedubs ceedubs closed this as completed Jul 27, 2016
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

4 participants