Skip to content

Instantly share code, notes, and snippets.

@jcazevedo
Forked from anonymous/gist:3847798
Created October 7, 2012 23:00
Show Gist options
  • Save jcazevedo/3849885 to your computer and use it in GitHub Desktop.
Save jcazevedo/3849885 to your computer and use it in GitHub Desktop.
Simple Non-Polymorphic Stack Machine
import scala.util.Random
object PStack {
type Any = PStack[_, _]
}
sealed trait PStack[A, B <: PStack.Any] {
def pop2: Option[(A, B)]
def push0[C](elem: C): PStack[C, PStack[A, B]] =
NonEmptyPStack(elem, this)
def push[C, D <: PStack.Any](op: Op[A, B, C, D]): PStack[C, D] =
op.execute(this)
def head: Option[A]
}
case class EmptyPStack()
extends PStack[Unit, EmptyPStack] {
def pop2 = None
def head = None
}
case class NonEmptyPStack[A, B <: PStack.Any](top: A, rest: B)
extends PStack[A, B] {
def pop2 = Some((top, rest))
def head = Some(top)
}
sealed trait Op[A, B <: PStack.Any, C, D <: PStack.Any] {
def execute(ctx: PStack[A, B]): PStack[C, D]
}
case class Op0[A, B, C <: PStack.Any](method: () => A)
extends Op[B, C, A, PStack[B, C]] {
def execute(ctx: PStack[B, C]) = {
ctx.push0(method())
}
}
case class Op1[A, B, C, D <: PStack.Any](method: A => B)
extends Op[A, PStack[C, D], B, PStack[C, D]] {
def execute(ctx: PStack[A, PStack[C, D]]) = {
val (a, q) = ctx.pop2.get
q.push0(method(a))
}
}
case class Op2[A, B, C, D, E, F <: PStack.Any](method: (A, B) => C)
extends Op[A, PStack[B, PStack[E, F]], C, PStack[E, F]] {
def execute(ctx: PStack[A, PStack[B, PStack[E, F]]]) = {
val (a, p) = ctx.pop2.get
val (b, q) = p.pop2.get
q.push0(method(a, b))
}
}
object Op {
implicit def elemToPush[A, B, C <: PStack.Any](elem: A): Op0[A, B, C] = Op0({ () => elem })
implicit def function0ToOp[A, B, C <: PStack.Any](elem: (() => A)): Op0[A, B, C] = Op0(elem)
implicit def function1ToOp[A, B, C, D <: PStack.Any](elem: (A => B)): Op1[A, B, C, D] = Op1(elem)
implicit def function2ToOp[A, B, C, D, E, F <: PStack.Any](elem: (A, B) => C): Op2[A, B, C, D, E, F] = Op2(elem)
}
object Main extends App {
import Op._
val stack =
EmptyPStack()
.push(3)
.push({ a: Int => a * a })
.push({ () => new Random().nextInt(10) })
.push(5)
.push({ (a: Int, b: Int) => a + b })
.push({ (a: Int, b: Int) => a + b })
.push("The result is ")
.push({ (a: String, b: Int) => a + ": " + b })
println(stack)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment