Last active
February 2, 2021 10:12
-
-
Save lewapek/e686b94fe91a74df58b75efb0fa9c00f to your computer and use it in GitHub Desktop.
Expression problem in Scala
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
// 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