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

Add cats.io and IO monad #907

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -95,22 +95,22 @@ lazy val cats = project.in(file("."))
.settings(moduleName := "root")
.settings(catsSettings)
.settings(noPublishSettings)
.aggregate(catsJVM, catsJS)
.dependsOn(catsJVM, catsJS, testsJVM % "test-internal -> test", bench % "compile-internal;test-internal -> test")
.aggregate(catsJVM, catsJS, ioJVM, ioJS)
.dependsOn(catsJVM, catsJS, ioJVM, ioJS, testsJVM % "test-internal -> test", bench % "compile-internal;test-internal -> test")

lazy val catsJVM = project.in(file(".catsJVM"))
.settings(moduleName := "cats")
.settings(catsSettings)
.settings(commonJvmSettings)
.aggregate(macrosJVM, coreJVM, lawsJVM, testsJVM, jvm, docs, bench)
.dependsOn(macrosJVM, coreJVM, lawsJVM, testsJVM % "test-internal -> test", jvm, bench % "compile-internal;test-internal -> test")
.aggregate(macrosJVM, coreJVM, ioJVM, lawsJVM, testsJVM, jvm, docs, bench)
.dependsOn(macrosJVM, coreJVM, ioJVM, lawsJVM, testsJVM % "test-internal -> test", jvm, bench % "compile-internal;test-internal -> test")

lazy val catsJS = project.in(file(".catsJS"))
.settings(moduleName := "cats")
.settings(catsSettings)
.settings(commonJsSettings)
.aggregate(macrosJS, coreJS, lawsJS, testsJS, js)
.dependsOn(macrosJS, coreJS, lawsJS, testsJS % "test-internal -> test", js)
.aggregate(macrosJS, coreJS, ioJS, lawsJS, testsJS, js)
.dependsOn(macrosJS, coreJS, ioJS, lawsJS, testsJS % "test-internal -> test", js)
.enablePlugins(ScalaJSPlugin)


Expand Down Expand Up @@ -139,6 +139,17 @@ lazy val core = crossProject.crossType(CrossType.Pure)
lazy val coreJVM = core.jvm
lazy val coreJS = core.js

lazy val io = crossProject.crossType(CrossType.Pure)
.dependsOn(core, tests % "test-internal -> test")
.settings(moduleName := "cats-io")
.settings(catsSettings: _*)
.jsSettings(commonJsSettings: _*)
.jsSettings()
.jvmSettings(commonJvmSettings: _*)

lazy val ioJVM = io.jvm
lazy val ioJS = io.js

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the new module needs adding to the command aliases (buildJVM / validateJVM) below & scripts/travis_publish.sh

lazy val laws = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core)
.settings(moduleName := "cats-laws")
Expand Down Expand Up @@ -259,11 +270,11 @@ lazy val publishSettings = Seq(
) ++ credentialSettings ++ sharedPublishSettings ++ sharedReleaseProcess

// These aliases serialise the build for the benefit of Travis-CI.
addCommandAlias("buildJVM", ";macrosJVM/compile;coreJVM/compile;coreJVM/test;lawsJVM/compile;testsJVM/test;jvm/test;bench/test")
addCommandAlias("buildJVM", ";macrosJVM/compile;coreJVM/compile;coreJVM/test;ioJVM/compile;lawsJVM/compile;testsJVM/test;ioJVM/test;jvm/test;bench/test")

addCommandAlias("validateJVM", ";scalastyle;buildJVM;makeSite")

addCommandAlias("validateJS", ";macrosJS/compile;coreJS/compile;lawsJS/compile;testsJS/test;js/test")
addCommandAlias("validateJS", ";macrosJS/compile;coreJS/compile;ioJS/compile;ioJS/test;lawsJS/compile;testsJS/test;js/test")

addCommandAlias("validate", ";validateJS;validateJVM")

Expand Down
43 changes: 43 additions & 0 deletions io/src/main/scala/cats/io/IO.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cats
package io

import cats.data.Xor

import java.lang.Throwable

import scala.reflect.ClassTag

final class IO[A] private[io] (private val eval: Eval[A]) extends Serializable {
def unsafePerformIO(): A = eval.value

def catchOnly[T >: Null <: Throwable: ClassTag]: IO[T Xor A] =
new IO(Eval.always(Xor.catchOnly[T](eval.value)))

def catchNonFatal: IO[Throwable Xor A] =
new IO(Eval.always(Xor.catchNonFatal(eval.value)))

def map[B](f: A => B): IO[B] =
new IO(eval.map(f))

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

object IO extends IOInstances {
/** Capture a side-effecting expression as a new IO primitive. */
def always[A](a: => A): IO[A] =
new IO[A](Eval.always(a))

def pure[A](a: A): IO[A] =
new IO[A](Eval.now(a))
}

trait IOInstances {
implicit val ioInstances: Monad[IO] =
new Monad[IO] {
def pure[A](a: A): IO[A] = IO.pure(a)
override def pureEval[A](a: Eval[A]): IO[A] = new IO(a)
def flatMap[A, B](ma: IO[A])(f: A => IO[B]): IO[B] = ma.flatMap(f)
override def map[A, B](ma: IO[A])(f: A => B): IO[B] = ma.map(f)
}
}
15 changes: 15 additions & 0 deletions io/src/test/scala/cats/io/IOSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cats
package io

import cats.laws.discipline.arbitrary._

import org.scalacheck.Arbitrary
import org.scalacheck.Arbitrary.arbitrary

trait IOSuite {
implicit def ioArbitrary[A: Arbitrary]: Arbitrary[IO[A]] =
Arbitrary(arbitrary[Eval[A]].map(ea => new IO(ea)))

implicit def ioEq[A: Eq]: Eq[IO[A]] =
Eq.by(_.unsafePerformIO())
}
11 changes: 11 additions & 0 deletions io/src/test/scala/cats/io/IOTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cats
package io

import cats.laws.discipline.{MonadTests, SerializableTests}
import cats.tests.CatsSuite
import cats.laws.discipline.eq.tuple3Eq

class IOTests extends CatsSuite with IOSuite {
checkAll("IO", MonadTests[IO].monad[Int, String, Double])
checkAll("Monad[IO]", SerializableTests.serializable(Monad[IO]))
}
2 changes: 1 addition & 1 deletion scripts/travis-publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fi
sbt_cmd="sbt ++$TRAVIS_SCALA_VERSION"

coverage="$sbt_cmd coverage validateJVM coverageReport && bash <(curl -s https://codecov.io/bash)"
scala_js="$sbt_cmd macrosJS/compile coreJS/compile lawsJS/compile && $sbt_cmd testsJS/test && $sbt_cmd js/test"
scala_js="$sbt_cmd macrosJS/compile coreJS/compile ioJS/compile lawsJS/compile && $sbt_cmd testsJS/test && $sbt_cmd js/test && $sbt_cmd ioJS/test"
scala_jvm="$sbt_cmd validateJVM"

run_cmd="$coverage && $scala_js && $scala_jvm $publish_cmd"
Expand Down