alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (FreeAp.scala)

This example Scala source code file (FreeAp.scala) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Scala by Example" TM.

Learn more about this Scala project at its project page.

Java - Scala tags/keywords

applicative, const, freeap, pure, unapply

The FreeAp.scala Scala example source code

package scalaz

/**
 * Free applicative functors. Less expressive than free monads, but more
 * flexible to inspect and interpret.
 */
sealed abstract class FreeAp[F[_],A] {
  import FreeAp._

  /**
   * The canonical natural transformation that interprets this free
   * program by giving it the semantics of the applicative functor `G`.
   * Not tail-recursive unless `G` is a free monad.
   */
  def foldMap[G[_]:Applicative](f: F ~> G): G[A] =
    this match {
      case Pure(x) => Applicative[G].pure(x)
      case x@Ap() => Applicative[G].ap(f(x.v()))(x.k() foldMap f)
    }

  /** Provides access to the first instruction of this program, if present */
  def para[B](pure: A => B, ap: λ[α => (F[α], FreeAp[F, α => A])] ~> λ[α => B]): B =
    this match {
      case Pure(x) => pure(x)
      case x@Ap() => ap(x.v() -> x.k())
    }

  /**
   * Performs a monoidal analysis over this free program. Maps the
   * effects in `F` to values in the monoid `M`, discarding the values
   * of those effects.
   * Example:
   *
   * {{{
   * def count[F[_],B](p: FreeAp[F,B]): Int =
   *   p.analyze(new (F ~> λ[α => Int]) {
   *     def apply[A](a: F[A]) = 1
   *   })
   * }}}
   */
  def analyze[M:Monoid](f: F ~> λ[α => M]): M =
    foldMap[Const[M, ?]](new (F ~> Const[M, ?]) {
      def apply[X](x: F[X]): Const[M,X] = Const(f(x))
    }).getConst

  /**
   * The natural transformation from `FreeAp[F,_]` to `FreeAp[G,_]`
   */
  def hoist[G[_]](f: F ~> G): FreeAp[G,A] = this match {
    case Pure(a) => Pure(a)
    case x@Ap() => FreeAp(f(x.v()), x.k() hoist f)
  }

  /**
   * Interprets this free `F` program using the semantics of the
   * `Applicative` instance for `F`.
   */
  def retract(implicit F: Applicative[F]): F[A] = this match {
    case Pure(a) => Applicative[F].pure(a)
    case x@Ap() => Applicative[F].ap(x.v())(x.k().retract)
  }

  /**
   * Embeds this program in the free monad on `F`.
   */
  def monadic: Free[F,A] =
    foldMap[Free[F,?]](new (F ~> Free[F,?]) {
      def apply[B](fb: F[B]) = Free.liftF(fb)
    })

  /** Idiomatic function application */
  def ap[B](f: FreeAp[F, A => B]): FreeAp[F,B] = f match {
    case Pure(g) => map(g)
    case x@Ap() => FreeAp(x.v(), ap(x.k().map(g => (a:A) => (b:x.I) => g(b)(a))))
  }

  /** Append a function to the end of this program */
  def map[B](f: A => B): FreeAp[F,B] = this match {
    case Pure(a) => Pure(f(a))
    case x@Ap() => FreeAp(x.v(), x.k().map(f compose _))
  }
}

object FreeAp {
  implicit def freeInstance[F[_]]: Applicative[FreeAp[F, ?]] =
    new Applicative[FreeAp[F, ?]] {
      def point[A](a: => A) = FreeAp.point(a)
      def ap[A,B](fa: => FreeAp[F,A])(ff: => FreeAp[F, A => B]) = fa ap ff
    }

  /** Return a value in a free applicative functor */
  def point[F[_],A](a: A): FreeAp[F,A] = Pure(a)

  /** Return a value in a free applicative functor. Alias for `point`. */
  def pure[F[_],A](a: A): FreeAp[F,A] = point(a)

  /** Lift a value in `F` into the free applicative functor on `F` */
  def lift[F[_],A](x: => F[A]): FreeAp[F, A] = FreeAp(x, Pure((a: A) => a))

  /** A version of `lift` that infers the nested type constructor. */
  def liftU[FA](x: => FA)(implicit FA: Unapply[Functor, FA]): FreeAp[FA.M, FA.A] =
    lift(FA(x))

  private [scalaz] case class Pure[F[_],A](a: A) extends FreeAp[F,A]
  private abstract case class Ap[F[_],A]() extends FreeAp[F,A] {
    type I
    val v: () => F[I]
    val k: () => FreeAp[F, I => A]
  }

  /**
   * Add an effect to the front of a program that produces a continuation for it.
   */
  def apply[F[_],A,B](value: => F[A], function: => FreeAp[F, A => B]): FreeAp[F,B] =
    new Ap[F,B] {
      type I = A
      val v = () => value
      val k = () => function
    }
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala FreeAp.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.