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

org.specs2.fp.Traverse.scala Maven / Gradle / Ivy

The newest version!
package org.specs2.fp

/**
 * Inspired from the scalaz (https://github.com/scalaz/scalaz) project
 */
trait Traverse[F[_]] extends Functor[F] {

  /** Transform `fa` using `f`, collecting all the `G`s with `ap`. */
  def traverseImpl[G[_]: Applicative,A,B](fa: F[A])(f: A => G[B]): G[F[B]]

  class Traversal[G[_]](implicit G: Applicative[G]) {
    def run[A,B](fa: F[A])(f: A => G[B]): G[F[B]] = traverseImpl[G,A,B](fa)(f)
  }

  def traversal[G[_]:Applicative]: Traversal[G] =
    new Traversal[G]

  def traverse[G[_]: Applicative,A,B](fa: F[A])(f: A => G[B]): G[F[B]] =
    traversal[G].run(fa)(f)

  final def traverseM[A, G[_], B](fa: F[A])(f: A => G[F[B]])(implicit G: Applicative[G], F: Monad[F]): G[F[B]] =
    G.map(G.traverse(fa)(f)(this))(F.join)

  /** Traverse with the identity function. */
  def sequence[G[_]: Applicative,A](fga: F[G[A]]): G[F[A]] =
    traversal[G].run[G[A], A](fga)(ga => ga)

}

object Traverse {
  @inline def apply[F[_]](implicit F: Traverse[F]): Traverse[F] = F

  implicit val listInstance: Traverse[List] = new Traverse[List] {
    def traverseImpl[G[_]: Applicative, A, B](fa: List[A])(f: A => G[B]): G[List[B]] = {
      val g = Applicative.apply[G]
      fa match {
        case Nil => g.point(Nil)
        case h :: t => g.apply2(traverseImpl(t)(f), f(h))((r, b) => b :: r)
      }
    }

    def map[A, B](fa: List[A])(f: A => B): List[B] =
      fa.map(f)
  }

  implicit def optionInstance[L]: Traverse[Option] = new Traverse[Option] {
    def traverseImpl[G[_]: Applicative, A, B](fa: Option[A])(f: A => G[B]): G[Option[B]] = {
      val g = Applicative.apply[G]
      fa match {
        case None    => g.point(None)
        case Some(a) => g.map(f(a))(Some.apply)
      }
    }

    def map[A, B](fa: Option[A])(f: A => B): Option[B] =
      fa.map(f)
  }

  implicit def eitherInstance[L]: Traverse[Either[L, *]] = new Traverse[Either[L, *]] {
    def traverseImpl[G[_]: Applicative, A, B](fa: Either[L, A])(f: A => G[B]): G[Either[L, B]] = {
      val g = Applicative.apply[G]
      fa match {
        case Left(l)  => g.point(Left(l))
        case Right(a) => g.map(f(a))(Right.apply)
      }
    }

    def map[A, B](fa: Either[L, A])(f: A => B): Either[L, B] =
      fa match {
        case Left(l)  => Left(l)
        case Right(a) => Right(f(a))
      }
  }
}


trait TraverseSyntax {

  implicit class TraverseOps[F[_] : Traverse, A](fa: F[A]) {
    def traverse[G[_] : Applicative, B](f: A => G[B]): G[F[B]] =
      Traverse.apply[F].traverse(fa)(f)
  }

  implicit class SequenceOps[F[_] : Traverse, G[_] : Applicative, A](fa: F[G[A]]) {
    def sequence: G[F[A]] =
      Traverse.apply[F].sequence(fa)
  }
}

object TraverseSyntax extends TraverseSyntax




© 2015 - 2024 Weber Informatics LLC | Privacy Policy