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

scalaz.UnwriterT.scala Maven / Gradle / Ivy

package scalaz

import Id._

/**
 * This data type is isomorphic to `WriterT`, however, it is NOT a monad.
 *
 * It implements flatMap+map and drops the write value. There is no `Monoid` or `Semigroup` required. There is no `point` operation.
 * You can switch between `WriterT` and `UnwriterT` with `unary_+` and `unary_-`.
 */
final case class UnwriterT[F[_], U, A](run: F[(U, A)]) { self =>
  import UnwriterT._

  def on: WriterT[F, U, A] =
    WriterT(run)

  /** alias for `on` */
  def unary_+ : WriterT[F, U, A] =
    WriterT(run)

  def mapValue[X, B](f: ((U, A)) => (X, B))(implicit F: Functor[F]): UnwriterT[F, X, B] =
    unwriterT(F.map(run)(f))

  def mapUnwritten[X](f: U => X)(implicit F: Functor[F]): UnwriterT[F, X, A] =
    mapValue(wa => (f(wa._1), wa._2))

  def unwritten(implicit F: Functor[F]): F[U] =
    F.map(run)(_._1)

  def value(implicit F: Functor[F]): F[A] =
    F.map(run)(_._2)

  def swap(implicit F: Functor[F]): UnwriterT[F, A, U] =
    mapValue(wa => (wa._2, wa._1))

  def map[B](f: A => B)(implicit F: Functor[F]): UnwriterT[F, U, B] =
    unwriterT(F.map(run)(wa => (wa._1, f(wa._2))))


  def ap[B](f: => UnwriterT[F, U, A => B])(implicit F: Apply[F]): UnwriterT[F, U, B] =
    unwriterT {
      F.apply2(f.run, run) {
        case ((w1, fab), (_, a)) => (w1, fab(a))
      }
    }

  def flatMap[B](f: A => UnwriterT[F, U, B])(implicit F: Bind[F]): UnwriterT[F, U, B] =
    unwriterT(F.bind(run){wa =>
      val z = f(wa._2).run
      F.map(z)(wb => (wa._1, wb._2))
    })

  def traverse[G[_], B](f: A => G[B])(implicit G: Applicative[G], F: Traverse[F]): G[UnwriterT[F, U, B]] = {
    G.map(F.traverse(run){
      case (w, a) => G.map(f(a))(b => (w, b))
    })(UnwriterT(_))
  }

  def foldRight[B](z: => B)(f: (A, => B) => B)(implicit F: Foldable[F]) =
    F.foldr(run, z) { a => b =>
      f(a._2, b)
    }

  def bimap[C, D](f: U => C, g: A => D)(implicit F: Functor[F]) =
    unwriterT[F, C, D](F.map(run)({
      case (a, b) => (f(a), g(b))
    }))

  def leftMap[C](f: U => C)(implicit F: Functor[F]): UnwriterT[F, C, A] =
    bimap(f, identity)

  def bitraverse[G[_], C, D](f: U => G[C], g: A => G[D])(implicit G: Applicative[G], F: Traverse[F]) =
    G.map(F.traverse[G, (U, A), (C, D)](run) {
      case (a, b) => G.tuple2(f(a), g(b))
    })(unwriterT(_))

  def wpoint[G[_]](implicit F: Functor[F], P: Applicative[G]): UnwriterT[F, G[U], A] =
    unwriterT(F.map(self.run) {
      case (u, a) => (P.point(u), a)
    })

  def colocal[X](f: U => X)(implicit F: Functor[F]): UnwriterT[F, X, A] = mapUnwritten(f)
}

object UnwriterT extends UnwriterTInstances with UnwriterTFunctions

sealed abstract class UnwriterTInstances2 {
  implicit def unwriterTFunctor[F[_], W](implicit F0: Functor[F]): Functor[UnwriterT[F, W, ?]] =
    new UnwriterTFunctor[F, W] {
      implicit def F = F0
    }
}

sealed abstract class UnwriterTInstances1 extends UnwriterTInstances2 {
  implicit def unwriterTApply[F[_], W](implicit F0: Apply[F]): Apply[UnwriterT[F, W, ?]] =
    new UnwriterTApply[F, W] {
      implicit def F = F0
    }
}

sealed abstract class UnwriterTInstances0 extends UnwriterTInstances1 {
  implicit def unwriterTBifunctor[F[_]](implicit F0: Functor[F]): Bifunctor[UnwriterT[F, ?, ?]] =
    new UnwriterTBifunctor[F] {
      implicit def F = F0
    }
  implicit def unwriterTBind[F[_], W](implicit F0: Bind[F]): Bind[UnwriterT[F, W, ?]] =
    new UnwriterTBind[F, W] {
      implicit def F = F0
    }
  implicit def unwriterTFoldable[F[_], W](implicit F0: Foldable[F]): Foldable[UnwriterT[F, W, ?]] =
    new UnwriterTFoldable[F, W] {
      implicit def F = F0
    }
  implicit def unwriterTEqual[F[_], W, A](implicit E: Equal[F[(W, A)]]): Equal[UnwriterT[F, W, A]] =
    E.contramap((_: UnwriterT[F, W, A]).run)
}

sealed abstract class UnwriterTInstances extends UnwriterTInstances0 {
  implicit def unwriterTBitraverse[F[_]](implicit F0: Traverse[F]): Bitraverse[UnwriterT[F, ?, ?]] =
    new UnwriterTBitraverse[F] {
      implicit def F = F0
    }
  implicit def unwriterComonad[W]: Comonad[Unwriter[W, ?]] =
    new UnwriterComonad[W] {
      implicit def F = implicitly
    }
  implicit def unwriterTTraverse[F[_], W](implicit F0: Traverse[F]): Traverse[UnwriterT[F, W, ?]] =
    new UnwriterTTraverse[F, W] {
      implicit def F = F0
    }
  implicit def unwriterEqual[W, A](implicit W: Equal[W], A: Equal[A]): Equal[Unwriter[W, A]] = {
    import std.tuple._
    Equal[(W, A)].contramap((_: Unwriter[W, A]).run)
  }
}

trait UnwriterTFunctions {
  def unwriterT[F[_], W, A](v: F[(W, A)]): UnwriterT[F, W, A] = UnwriterT(v)


  def unwriter[W, A](v: (W, A)): Unwriter[W, A] =
    unwriterT[Id, W, A](v)

  def tell[W](w: W): Unwriter[W, Unit] = unwriter((w, ()))

  def unput[F[_], W, A](value: F[A])(w: W)(implicit F: Functor[F]): UnwriterT[F, W, A] =
    UnwriterT(F.map(value)(a => (w, a)))

  /** Puts the written value that is produced by applying the given function into a unwriter transformer and associates with `value` */
  def unputWith[F[_], W, A](value: F[A])(w: A => W)(implicit F: Functor[F]): UnwriterT[F, W, A] =
    UnwriterT(F.map(value)(a => (w(a), a)))

}

//
// Type class implementation traits
//

private trait UnwriterTFunctor[F[_], W] extends Functor[UnwriterT[F, W, ?]] {
  implicit def F: Functor[F]

  override def map[A, B](fa: UnwriterT[F, W, A])(f: A => B) = fa map f
}

private trait UnwriterTApply[F[_], W] extends Apply[UnwriterT[F, W, ?]] with UnwriterTFunctor[F, W] {
  implicit def F: Apply[F]

  override def ap[A, B](fa: => UnwriterT[F, W, A])(f: => UnwriterT[F, W, A => B]) = fa ap f
}


private trait UnwriterTBind[F[_], W] extends Bind[UnwriterT[F, W, ?]] with UnwriterTApply[F, W] {
  implicit def F: Bind[F]

  def bind[A, B](fa: UnwriterT[F, W, A])(f: A => UnwriterT[F, W, B]) = fa flatMap f
}

private trait UnwriterTFoldable[F[_], W] extends Foldable.FromFoldr[UnwriterT[F, W, ?]] {
  implicit def F: Foldable[F]

  override def foldRight[A, B](fa: UnwriterT[F, W, A], z: => B)(f: (A, => B) => B) = fa.foldRight(z)(f)
}

private trait UnwriterTTraverse[F[_], W] extends Traverse[UnwriterT[F, W, ?]] with UnwriterTFoldable[F, W] {
  implicit def F: Traverse[F]

  def traverseImpl[G[_]: Applicative, A, B](fa: UnwriterT[F, W, A])(f: A => G[B]) = fa traverse f
}

private trait UnwriterTBifunctor[F[_]] extends Bifunctor[UnwriterT[F, ?, ?]] {
  implicit def F: Functor[F]

  override def bimap[A, B, C, D](fab: UnwriterT[F, A, B])(f: A => C, g: B => D) =
    fab.bimap(f, g)
}

private trait UnwriterTBitraverse[F[_]] extends Bitraverse[UnwriterT[F, ?, ?]] with UnwriterTBifunctor[F] {
  implicit def F: Traverse[F]

  def bitraverseImpl[G[_]: Applicative, A, B, C, D](fab: UnwriterT[F, A, B])(f: A => G[C], g: B => G[D]) =
    fab.bitraverse(f, g)
}

private trait UnwriterComonad[W] extends Comonad[Unwriter[W, ?]] with UnwriterTFunctor[Id, W] {

  override def cojoin[A](fa: Unwriter[W, A]): Unwriter[W, Unwriter[W, A]] =
    Unwriter(fa.unwritten, fa)

  override def cobind[A, B](fa: Unwriter[W, A])(f: (Unwriter[W, A]) => B): Unwriter[W, B] =
    Unwriter(fa.unwritten, f(fa))
  def copoint[A](p: Unwriter[W, A]): A = p.value
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy