Skip to content

Instantly share code, notes, and snippets.

@Ghurtchu
Last active June 26, 2022 13:48
Show Gist options
  • Save Ghurtchu/c5af4851ce4f1e10d203c58c14364080 to your computer and use it in GitHub Desktop.
Save Ghurtchu/c5af4851ce4f1e10d203c58c14364080 to your computer and use it in GitHub Desktop.
ArithmeticExpressionsDSL.scala
import scala.language.implicitConversions
object ArithmeticExpressionsDSL extends scala.App {
sealed trait Expr
object Expr {
final case class Literal private(n: Int) extends Expr
final case class Negate private(expr: Expr) extends Expr
final case class Add private (left: Expr, right: Expr) extends Expr
final case class Subtract private (left: Expr, right: Expr) extends Expr
final case class Multiply private (left: Expr, right: Expr) extends Expr
final case class Divide private (left: Expr, right: Expr) extends Expr
def apply(expr: Expr): Int = expr match {
case Literal(n) => n
case Negate(expr) => -apply(expr)
case Add(left, right) => apply(left) + apply(right)
case Subtract(left, right) => apply(left) - apply(right)
case Multiply(left, right) => apply(left) * apply(right)
case Divide(left, right) => right match {
case Literal(n) if n == 0 => throw new ArithmeticException("Division by zero")
case _ => apply(left) / apply(right)
}
}
def stringify(expr: Expr): String = expr match {
case Literal(n) => s"$n"
case Negate(expr) => s"-$expr"
case Add(left, right) => s"(${stringify(left)} + ${stringify(right)})"
case Subtract(left, right) => s"(${stringify(left)} - ${stringify(right)})"
case Multiply(left, right) => s"(${stringify(left)} * ${stringify(right)})"
case Divide(left, right) => s"(${stringify(left)} / ${stringify(right)})"
}
def neg(e: Expr): Expr = Negate(e)
def add(left: Expr, right: Expr): Expr = Add(left, right)
def sub(left: Expr, right: Expr): Expr = Subtract(left, right)
def mul(left: Expr, right: Expr): Expr = Multiply(left, right)
def div(left: Expr, right: Expr): Expr = Divide(left, right)
}
implicit def intToLiteral(n: Int): Expr = Expr.Literal(n)
implicit class ShowExpr(expr: Expr) {
def show(): Unit = {
val expression: String = Expr.stringify(expr)
val result : Int = Expr(expr)
println(s"$expression = $result")
}
def evaluate: Int = Expr(expr)
}
import Expr._
val expr: Expr = mul(20, sub(10, add(1, div(5, 3))))
assert(expr.evaluate == 160)
expr.show()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment