All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalaz.ioeffect.IOInstances.scala Maven / Gradle / Ivy

// Copyright (C) 2017 John A. De Goes. All rights reserved.
package scalaz
package ioeffect

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]
}

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]
}

sealed abstract class IOInstance2 {
  implicit def ioMonadPlus[E: Monoid]: MonadPlus[IO[E, ?]] with BindRec[IO[E, ?]] = new IOMonadPlus[E]
}

private class IOMonad[E] extends Monad[IO[E, ?]] with BindRec[IO[E, ?]] {
  override def map[A, B](fa: IO[E, A])(f: A => B): IO[E, B]         = fa.map(f)
  override def point[A](a: => A): IO[E, A]                          = IO.point(a)
  override def bind[A, B](fa: IO[E, A])(f: A => IO[E, B]): IO[E, B] = fa.flatMap(f)
  override def tailrecM[A, B](f: A => IO[E, A \/ B])(a: A): IO[E, B] =
    f(a).flatMap(_.fold(tailrecM(f), point(_)))

  // backport https://github.com/scalaz/scalaz/pull/1894
  override def apply2[A, B, C](fa: => IO[E, A], fb: => IO[E, B])(f: (A, B) => C): IO[E, C] = {
    val fb0 = Need(fb)
    bind(fa)(a => map(fb0.value)(b => f(a, b)))
  }
}

private class IOMonadError[E] extends IOMonad[E] with MonadError[IO[E, ?], E] {
  override def handleError[A](fa: IO[E, A])(f: E => IO[E, A]): IO[E, A] = fa.catchAll(f)
  override def raiseError[A](e: E): IO[E, A]                            = IO.fail(e)
}

// lossy, throws away errors using the "first success" interpretation of Plus
private trait IOPlus[E] extends Plus[IO[E, ?]] {
  override def plus[A](a: IO[E, A], b: => IO[E, A]): IO[E, A] = a.catchAll(_ => b)
}

// annoyingly, we just need M.zero
private class IOMonadPlus[E](implicit M: Monoid[E]) extends IOMonadError[E] with IOPlus[E] with MonadPlus[IO[E, ?]] {
  override def empty[A]: IO[E, A] = raiseError(M.zero)
}

private trait IOBifunctor extends Bifunctor[IO] {
  override def bimap[A, B, C, D](fab: IO[A, B])(f: A => C, g: B => D): IO[C, D] =
    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] = {
    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] =
    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] =
    Tag(Tag.unwrap(fa).par(Tag.unwrap(fb)).map(f.tupled))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy