Skip to content

Instantly share code, notes, and snippets.

@lewapek
Last active February 2, 2021 10:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lewapek/e686b94fe91a74df58b75efb0fa9c00f to your computer and use it in GitHub Desktop.
Save lewapek/e686b94fe91a74df58b75efb0fa9c00f to your computer and use it in GitHub Desktop.
Expression problem in Scala
// Expression problem in Scala
object OOP {
trait Expr {
def eval: Int
def show: String
}
case class Add(a: Expr, b: Expr) extends Expr {
override def eval: Int = a.eval + b.eval
override def show: String = "(" + a.show + ") + (" + b.show + ")"
}
case class Mul(a: Expr, b: Expr) extends Expr {
override def eval: Int = a.eval * b.eval
override def show: String = "(" + a.show + ") * (" + b.show + ")"
}
case class N(n: Int) extends Expr {
override def eval: Int = n
override def show: String = n.toString
}
case class Neg(e: Expr) extends Expr {
override def eval: Int = -e.eval
override def show: String = "-(" + e.show + ")"
}
val example: Expr = Add(Mul(N(3), N(2)), N(7))
println(example.eval)
val example2: Expr = Add(Mul(N(3), N(2)), Neg(N(7)))
println(example2.eval)
println(example2.show)
val xs: List[Expr] = List(N(7), N(5), N(13), Add(N(1), N(1)))
val res: List[Int] = xs.map(_.eval)
}
OOP
object FP {
sealed trait Expr
case class Add(a: Expr, b: Expr) extends Expr
case class Mul(a: Expr, b: Expr) extends Expr
case class N(n: Int) extends Expr
case class Neg(e: Expr) extends Expr
def eval(e: Expr): Int = e match {
case Add(a, b) => eval(a) + eval(b)
case Mul(a, b) => eval(a) * eval(b)
case N(n) => n
case Neg(e) => -eval(e)
}
def show(e: Expr): String = e match {
case Add(a, b) => "(" + show(a) + ") + (" + show(b) + ")"
case Mul(a, b) => "(" + show(a) + ") * (" + show(b) + ")"
case N(n) => n.toString
case Neg(e) => "-(" + show(e) + ")"
}
val example: Expr = Add(Mul(N(3), N(2)), N(7))
println(eval(example))
val example2: Expr = Add(Mul(N(3), N(2)), Neg(N(7)))
println(eval(example2))
println(show(example2))
val xs: List[Expr] = List(N(7), N(5), N(13), Add(N(1), N(1)))
val res: List[Int] = xs.map(eval)
}
FP
object TC {
sealed trait Expr
case class Add[A <: Expr, B <: Expr](a: A, b: B) extends Expr
case class Mul[A <: Expr, B <: Expr](a: A, b: B) extends Expr
case class N(n: Int) extends Expr
case class Neg[A <: Expr](a: A) extends Expr
trait Show[T] {
def show(t: T): String
}
object Show {
def apply[A: Show]: Show[A] = implicitly[Show[A]]
implicit def showAdd[A <: Expr: Show, B <: Expr: Show]: Show[Add[A, B]] = new Show[Add[A, B]] {
override def show(t: Add[A, B]): String =
"(" + Show[A].show(t.a) + ") + (" + Show[B].show(t.b) + ")"
}
implicit def showMul[A <: Expr: Show, B <: Expr: Show]: Show[Mul[A, B]] = new Show[Mul[A, B]] {
override def show(t: Mul[A, B]): String =
"(" + Show[A].show(t.a) + ") * (" + Show[B].show(t.b) + ")"
}
implicit val showN: Show[N] = new Show[N] {
override def show(t: N): String = t.n.toString
}
implicit def showNeg[A <: Expr: Show]: Show[Neg[A]] = new Show[Neg[A]] {
override def show(t: Neg[A]): String = "-(" + Show[A].show(t.a) + ")"
}
}
trait Eval[T] {
def eval(t: T): Int
}
object Eval {
def apply[A: Eval]: Eval[A] = implicitly[Eval[A]]
implicit def evalAdd[A <: Expr: Eval, B <: Expr: Eval]: Eval[Add[A, B]] = new Eval[Add[A, B]] {
override def eval(t: Add[A, B]): Int = Eval[A].eval(t.a) + Eval[B].eval(t.b)
}
implicit def evalMul[A <: Expr: Eval, B <: Expr: Eval]: Eval[Mul[A, B]] = new Eval[Mul[A, B]] {
override def eval(t: Mul[A, B]): Int = Eval[A].eval(t.a) * Eval[B].eval(t.b)
}
implicit val evalN: Eval[N] = new Eval[N] {
override def eval(t: N): Int = t.n
}
implicit def evalNeg[A <: Expr: Eval]: Eval[Neg[A]] = new Eval[Neg[A]] {
override def eval(t: Neg[A]): Int = -Eval[A].eval(t.a)
}
}
val example = Add(Mul(N(3), N(2)), N(7))
val example2 = Add(Mul(N(3), N(2)), Neg(N(7)))
def eval[T <: Expr: Eval](t: T): Int = Eval[T].eval(t)
println(eval(example))
println(eval(example2))
implicit class EvalOps[T: Eval](t: T) {
def eval: Int = Eval[T].eval(t)
}
implicit class ShowOps[T: Show](t: T) {
def show: String = Show[T].show(t)
}
println(example.eval)
println(example2.eval)
println(example2.show)
val xs: List[Expr] = List(N(7), N(5), N(13), Add(N(1), N(1)))
// val res: List[Int] = xs.map(_.eval) // no typeclass instance for Expr
}
TC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment