-
-
Save jcazevedo/3849885 to your computer and use it in GitHub Desktop.
Simple Non-Polymorphic Stack Machine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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