Skip to content
This repository has been archived by the owner on Nov 5, 2022. It is now read-only.

Commit

Permalink
Make it easier to migrate legacy code (#53)
Browse files Browse the repository at this point in the history
* remove IO.apply and make it easier to capture Throwables in Task

* optimise IO.syncThrowable

* ignore an IO

* don't use aliases for instance declarations

* optimise syncThrowable

* disable scalafix
  • Loading branch information
fommil committed Jun 23, 2018
1 parent 50de9b8 commit 87deab2
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -3,7 +3,7 @@ jdk:
- openjdk8

script:
- sbt ";+check ;+cpl ;+lint ;+doc ;+test"
- sbt ";+check ;+cpl ;+test"
- if [ -z "$TRAVIS_PULL_REQUEST" ] && [ "${TRAVIS_REPO_SLUG}" == "scalaz/ioeffect" ] ; then sbt publish ; fi

before_cache:
Expand Down
25 changes: 14 additions & 11 deletions ioeffect/src/main/scala/scalaz/ioeffect/IO.scala
Expand Up @@ -3,12 +3,11 @@ package scalaz.ioeffect

import scala.annotation.switch
import scala.concurrent.duration._
import scalaz.{ -\/, @@, \/, \/-, unused, Maybe }
import scalaz.{ -\/, \/, \/-, unused, Maybe }
import scalaz.syntax.either._
import scalaz.ioeffect.Errors._
import scalaz.ioeffect.Errors.TerminatedException
import scalaz.Liskov.<~<
import scalaz.Tags.Parallel

import scala.concurrent.{ ExecutionContext, Future }

Expand Down Expand Up @@ -214,6 +213,12 @@ sealed abstract class IO[E, A] { self =>
case _ => new IO.Attempt(self)
}

/**
* Ignores the error and value of this IO, useful for explicitly acknowledging
* that a cleanup task will have its result ignored.
*/
def ignore: IO[Void, Unit] = attempt[Void].toUnit

/**
* When this action represents acquisition of a resource (for example,
* opening a file, launching a thread, etc.), `bracket` can be used to ensure
Expand Down Expand Up @@ -520,8 +525,6 @@ sealed abstract class IO[E, A] { self =>
}

object IO extends IOInstances {
type Par[e, a] = IO[e, a] @@ Parallel

final object Tags {
final val FlatMap = 0
final val Point = 1
Expand Down Expand Up @@ -689,11 +692,6 @@ object IO extends IOInstances {
*/
final def sync[E, A](effect: => A): IO[E, A] = new SyncEffect(() => effect)

/**
* To ease migration.
*/
final def apply[E, A](effect: => A): IO[E, A] = sync(effect)

/**
*
* Imports a synchronous effect into a pure `IO` value, translating any
Expand All @@ -704,8 +702,13 @@ object IO extends IOInstances {
* }}}
*/
final def syncThrowable[A](effect: => A): IO[Throwable, A] =
syncCatch(effect) {
case t: Throwable => t
IO.suspend {
try {
val a = effect
IO.sync(a)
} catch {
case t: Throwable => IO.fail(t)
}
}

/**
Expand Down
22 changes: 13 additions & 9 deletions ioeffect/src/main/scala/scalaz/ioeffect/IOInstances.scala
Expand Up @@ -2,19 +2,21 @@
package scalaz
package ioeffect

import Tags.Parallel

abstract class IOInstances extends IOInstances1 {
// cached for efficiency
implicit val taskInstances: MonadError[Task, Throwable] with BindRec[Task] with Plus[Task] =
new IOMonadError[Throwable] with IOPlus[Throwable]

implicit val taskParAp: Applicative[Task.Par] = new IOParApplicative[Throwable]
implicit val taskParAp: Applicative[λ[α => Task[α] @@ Parallel]] = new IOParApplicative[Throwable]
}

sealed abstract class IOInstances1 extends IOInstance2 {
implicit def ioInstances[E]: MonadError[IO[E, ?], E] with BindRec[IO[E, ?]] with Bifunctor[IO] with Plus[IO[E, ?]] =
new IOMonadError[E] with IOPlus[E] with IOBifunctor

implicit def ioParAp[E]: Applicative[IO.Par[E, ?]] = new IOParApplicative[E]
implicit def ioParAp[E]: Applicative[λ[α => IO[E, α] @@ Parallel]] = new IOParApplicative[E]
}

sealed abstract class IOInstance2 {
Expand Down Expand Up @@ -49,19 +51,21 @@ private trait IOBifunctor extends Bifunctor[IO] {
IO.absolve(fab.attempt.map(_.bimap(f, g)))
}

private class IOParApplicative[E] extends Applicative[IO.Par[E, ?]] {
override def point[A](a: => A): IO.Par[E, A] = Tag(IO.point(a))
override def ap[A, B](fa: => IO.Par[E, A])(f: => IO.Par[E, A => B]): IO.Par[E, B] = {
private class IOParApplicative[E] extends Applicative[λ[α => IO[E, α] @@ Parallel]] {
type Par[α] = IO[E, α] @@ Parallel

override def point[A](a: => A): Par[A] = Tag(IO.point(a))
override def ap[A, B](fa: => Par[A])(f: => Par[A => B]): Par[B] = {
lazy val fa0: IO[E, A] = Tag.unwrap(fa)
Tag(Tag.unwrap(f).flatMap(x => fa0.map(x)))
}

override def map[A, B](fa: IO.Par[E, A])(f: A => B): IO.Par[E, B] =
override def map[A, B](fa: Par[A])(f: A => B): Par[B] =
Tag(Tag.unwrap(fa).map(f))

override def apply2[A, B, C](
fa: => IO.Par[E, A],
fb: => IO.Par[E, B]
)(f: (A, B) => C): IO.Par[E, C] =
fa: => Par[A],
fb: => Par[B]
)(f: (A, B) => C): Par[C] =
Tag(Tag.unwrap(fa).par(Tag.unwrap(fb)).map(f.tupled))
}
5 changes: 1 addition & 4 deletions ioeffect/src/main/scala/scalaz/ioeffect/package.scala
Expand Up @@ -5,8 +5,6 @@ package scalaz
import scala.concurrent.{ ExecutionContext, Future }
import scala.concurrent.duration.Duration

import scalaz.Tags.Parallel

package object ioeffect {

implicit class IOVoidSyntax[A](val io: IO[Void, A]) extends AnyRef {
Expand All @@ -15,11 +13,10 @@ package object ioeffect {

type Task[A] = IO[Throwable, A]
object Task {
type Par[a] = Task[a] @@ Parallel
final def apply[A](effect: => A): Task[A] = IO.syncThrowable(effect)

final def now[A](effect: A): Task[A] = IO.now(effect)
final def point[A](effect: => A): Task[A] = IO.point(effect)
final def apply[A](effect: => A): Task[A] = IO.apply(effect)
final def sync[A](effect: => A): Task[A] = IO.sync(effect)
final def async[A](register: (ExitResult[Throwable, A] => Unit) => Unit): Task[A] = IO.async(register)

Expand Down
6 changes: 3 additions & 3 deletions project/ProjectPlugin.scala
Expand Up @@ -16,7 +16,7 @@ object ProjectKeys {

def SemanticDB =
addCompilerPlugin(
("org.scalameta" % "semanticdb-scalac" % "4.0.0-M3").cross(CrossVersion.full)
("org.scalameta" % "semanticdb-scalac" % "4.0.0-M4").cross(CrossVersion.full)
)

private val silencerVersion = "0.6"
Expand Down Expand Up @@ -71,9 +71,9 @@ object ProjectPlugin extends AutoPlugin {
testFrameworks in Test := Seq(TestFrameworks.Specs2, TestFrameworks.ScalaCheck, TestFrameworks.ScalaTest),
MonadicFor,
KindProjector,
SemanticDB,
//SemanticDB, // disabling scalafix until 0.6 stabilises
scalacOptions ++= Seq(
"-Yrangepos", // needed by semanticdb
//"-Yrangepos", // needed by semanticdb
"-unchecked",
"-explaintypes",
"-Ypartial-unification",
Expand Down

0 comments on commit 87deab2

Please sign in to comment.