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

scalaz.example.StateTUsage.scala Maven / Gradle / Ivy

package scalaz.example

import scalaz._

object StateTUsage extends App {
  import StateT._

  def f[M[+_]: Functor] {
    Functor[({type l[a] = StateT[M, Int, a]})#l]
  }

  def m[M[+_]: Monad] {
    Applicative[({type l[a] = StateT[M, Int, a]})#l]
    Monad[({type l[a] = StateT[M, Int, a]})#l]
    MonadState[({type f[s, a] = StateT[M, s, a]})#f, Int]
  }

  def state() {
    val state: State[String, Int] = State((x: String) => (x + 1, 0))
    val eval: Int = state.eval("")
    state.flatMap(_ => state)
  }
}

object FibStateExample extends App {
  val S = scalaz.StateT.stateMonad[(Int, Int)]
  import S.monadSyntax._
  import scalaz.State._
  import scalaz.std.list._

  val initialState = (0, 1)

  val (nextFib: State[(Int, Int), Int]) = for {
    s <- init:State[(Int, Int), (Int, Int)]
    (a,b) = s
    n = a + b
    _ <- put (b, n)
  } yield b // if we yield n, getNFibs gives you (1,2,3,5,8...)
            // yield b instead to get (1,1,2,3...)

  def getNFibs(k: Int): State[(Int, Int), List[Int]] = {
    nextFib.replicateM(k)
  }

  def getNthFib(k:Int): State[(Int, Int), Int] = {
    if (k == 0)
      pure(0) // will be thrown away
    else
      getNthFib(k - 1) >> nextFib
  }

  // run two examples through the magic of App
  println( getNthFib(5).eval( initialState ) )
  println( getNFibs(10).eval( initialState ) )
}

/** Simple call-by-need (i.e. lazy) interpreter for Lambda Calculus based off of
  * John Launchbury's "A Natural Semantics for Lazy Evaluation"
  * Uses the "Barendregt convention": All variable names are globally unique
  * (i.e. you cannot shadow variable names), and renames variables after substitution
  * to maintain this invariant.
  */
object LaunchburyInterpreter extends App {
  import scala.collection.immutable.HashMap
  import scalaz.StreamT._
  import scalaz.std.function._
  import scalaz.std.list._
  import scalaz.std.map._
  import scalaz.syntax.foldable._
  import scalaz.syntax.traverse._
  import scalaz.syntax.arrow._

  val S = scalaz.StateT.stateMonad[ReduceState]
  import S.monadSyntax._
  import scalaz.State._

  /** Simple lambda calculus Abstract Syntax Tree.
    * Note that that apply applies a let-bound argument to an Expr.
    * This is to make sharing easier, by ensuring that arguments are in the heap.
    */
  abstract sealed class Expr
  case class Lambda(name: String, term: Expr) extends Expr
  case class Apply(term: Expr, arg:String) extends Expr
  case class Var(name: String) extends Expr
  case class Let(bindings: Map[String, Expr], term: Expr) extends Expr

  // \x.x
  val example1 = Lambda("x", Var("x"))
  // let z = \y.y in (\x.x) z
  val example2 = Let( HashMap( "z" -> Lambda("y", Var("y")) )
                    , Apply(example1, "z")
                    )

  case class ReduceState( heap: Map[String, Expr]
                        , freshVars: Stream[String]
                        )

  private val initialState = ReduceState( HashMap()
                                        , Stream.from(1).map(x => "$" + x) // i.e. $1, $2, $3, ...
                                        )
  // Substitute new variable names in
  // e.g. sub(map("x" -> "y"), Var("x")) => Var("y")
  private def sub(m: Map[String, String])(e: Expr): Expr = {
    val subExpr = sub(m) _
    def subName(n: String) = if (m contains n) m(n) else n
    e match {
      case Lambda(z, e2) => Lambda(subName(z), subExpr(e2))
      case Apply(e2, z)  => Apply(subExpr(e2), subName(z))
      case Var(z)        => Var(subName(z))
      case Let(bs, e2)   => Let( bs.map(subName _ *** subExpr), subExpr(e2))
    }
  }


  // replaces every bound variable with a new, "fresh" variable
  // e.g. freshen(Lambda("x", Var("x"))).eval(initialState) => Lambda("$1", Var("$1"))
  private def freshen(e: Expr): State[ReduceState, Expr] = {
    val getFreshVar = for { s <- init: State[ReduceState,ReduceState]
                            ReduceState(_, f #:: fs) = s
                            _ <- modify((s:ReduceState) => s.copy(freshVars = fs))
                          } yield f
    // Lambda and Let define new bound variables, so we substitute fresh variables into them
    // Var and Apply just recursively traverse the AST
    e match {
      case Lambda(x, e2) => for { y <- getFreshVar
                                  e3 <- freshen( sub(HashMap(x -> y))(e2) )
                                } yield Lambda(y, e3)
      case Apply(e2, x)  => freshen(e2) >>= (e3 => pure(Apply(e3, x)))
      case Var(_)        => pure(e)
      case Let(bs, e2)   => for { fs <- getFreshVar.replicateM(bs.size)
                                  // Seq[((originalVar, Expr), freshVar)]
                                  newBindings = bs.toSeq.zip(fs)
                                  // sub(Map(originalVar -> freshVar))
                                  subs = sub( newBindings.map(tpl => tpl.copy(_1 = tpl._1._1)).toMap ) _
                                  // List[freshVar, Expr] - change to map when dolio's done
                                  bs2 = newBindings.map(tpl => tpl.copy(_2 = tpl._1._2, _1 = tpl._2)).toList
                                  e3 <- freshen( subs(e2) )
                                  freshendBs <- bs2.traverseS{case (x,e) => freshen( subs(e) ).map((x,_))}.map(_.toMap)
                                } yield Let(freshendBs, e3)

    }
  }

  /** performs "big-step" reduction: a single call maps a term to its final result
    * reduces lambda-terms to whnf or "weak head normal form".  For our purposes,
    * whnf means a lambda term (generally, it also refers to primitives and constructors,
    * which we've ommitted).
    */
  private def reduce(e:Expr): State[ReduceState, Expr] = {

    e match {
      case Lambda(x, e2) => pure(e) // as defined above, a Lambda is already in whnf
      case Apply(e2, x)  => reduce(e2) >>= { case Lambda(y, e3) => reduce( sub(HashMap(y -> x))(e3) )
                                             case _ => sys.error("Ill-typed lambda term")
                                           }
      case Var(x)        => for { state <- init:State[ReduceState, ReduceState]
                                  e2 = state.heap(x)
                                  _ <- modify((s:ReduceState) => s.copy(heap = s.heap - x))
                                  e3 <- reduce(e2)
                                  _ <- modify((s:ReduceState) => s.copy(heap = s.heap + ((x, e3))))
                                  freshendE <- freshen(e3)
                                } yield freshendE
     case Let(bs, e2)   => { val heapAdd = ((binding:(String, Expr)) =>
                                              modify((s:ReduceState) => s.copy(heap = s.heap + binding)))
                             bs.toList.traverseS(heapAdd) >> reduce(e2)
                           }
   }
 }

 def evaluate(e:Expr): Expr = reduce(e).eval(initialState)
 // run an example through the magic of App
 println(evaluate(example2))
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy