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

Scala example source code file (FreeUsage.scala)

This example Scala source code file (FreeUsage.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

app, danger, int, long, nextfloat, nextgaussian, nextint, nextprintablechar, randomreader, rngop, setseed

The FreeUsage.scala Scala example source code

package scalaz.example

import scalaz.{ Free, Monad, ~> }
import scalaz.std.function._
import scalaz.syntax.monad._
import scalaz.effect.IO

import scala.util.Random

// Example usage of free monad
object FreeUsage extends App {

  // An algebra of primitive operations in the context of a random number generator
  sealed trait RngOp[A]
  object RngOp {
    case object NextBoolean              extends RngOp[Boolean]
    case object NextDouble               extends RngOp[Double]
    case object NextFloat                extends RngOp[Float]
    case object NextGaussian             extends RngOp[Double]
    case object NextInt                  extends RngOp[Int]
    case class  NextIntInRange(max: Int) extends RngOp[Int]
    case object NextLong                 extends RngOp[Long]
    case object NextPrintableChar        extends RngOp[Char]
    case class  NextString(length: Int)  extends RngOp[String]
    case class  SetSeed(seed: Long)      extends RngOp[Unit]
  }

  // Free monad over the free functor of RngOp.
  type Rng[A] = Free[RngOp, A]

  // Smart constructors for Rng[A]
  val nextBoolean              = Free.liftF(RngOp.NextBoolean)
  val nextDouble               = Free.liftF(RngOp.NextDouble)
  val nextFloat                = Free.liftF(RngOp.NextFloat)
  val nextGaussian             = Free.liftF(RngOp.NextGaussian)
  val nextInt                  = Free.liftF(RngOp.NextInt)
  def nextIntInRange(max: Int) = Free.liftF(RngOp.NextIntInRange(max))
  val nextLong                 = Free.liftF(RngOp.NextLong)
  val nextPrintableChar        = Free.liftF(RngOp.NextPrintableChar)
  def nextString(length: Int)  = Free.liftF(RngOp.NextString(length))
  def setSeed(seed: Long)      = Free.liftF(RngOp.SetSeed(seed))

  // You can of course derive new operations from the primitives
  def nextNonNegativeInt       = nextInt.map(_.abs)
  def choose[A](h: A, tl: A*)  = nextIntInRange(tl.length + 1).map((h +: tl).apply)

  // Natural transformation to (Random => A)
  type RandomReader[A] = Random => A
  val toState: RngOp ~> RandomReader =
    new (RngOp ~> RandomReader) {
      def apply[A](fa: RngOp[A]) =
        fa match {
          case RngOp.NextBoolean       => _.nextBoolean
          case RngOp.NextDouble        => _.nextDouble
          case RngOp.NextFloat         => _.nextFloat
          case RngOp.NextGaussian      => _.nextGaussian
          case RngOp.NextInt           => _.nextInt
          case RngOp.NextIntInRange(n) => _.nextInt(n)
          case RngOp.NextLong          => _.nextLong
          case RngOp.NextPrintableChar => _.nextPrintableChar
          case RngOp.NextString(n)     => _.nextString(n)
          case RngOp.SetSeed(n)        => _.setSeed(n)
      }
    }

  // Now we have enough structure to run a program
  def runRng[A](program: Rng[A], seed: Long): A =
    program.foldMap(toState).apply(new Random(seed))

  // Syntax
  implicit class RngOps[A](ma: Rng[A]) {
    def exec(seed: Long): A = runRng(ma, seed)
    def liftIO: IO[A] = IO(System.currentTimeMillis).map(exec)
  }

  // An example that returns a pair of integers, a < 100, b < a and a color
  val prog: Rng[(Int, Int, String)] =
    for {
      a <- nextIntInRange(100)
      b <- nextIntInRange(a)
      c <- choose("red", "green", "blue")
    } yield (a, b, c)

  // Run that baby
  println(prog.exec(0L))   // pure! always returns (60,28,green)
  println(prog.exec(0L))   // exactly the same of course
  println(prog.exec(123L)) // (82,52,blue)
  println(prog.liftIO.unsafePerformIO) // DANGER: impure, who knows what will happen?

  // Of course all the normal combinators work
  println(nextBoolean.replicateM(10).exec(0L))

}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala FreeUsage.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.