Created
June 14, 2019 20:45
-
-
Save pinguinson/cd12868b86b44759c8af83c6776907a7 to your computer and use it in GitHub Desktop.
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 java.math.MathContext | |
sealed trait Expression { | |
def compute: BigDecimal | |
def show: String | |
} | |
sealed trait Amount[T] extends Expression | |
sealed trait Constant extends Expression | |
sealed abstract class ConstantAmount[T](currency: String) extends Amount[T] with Constant { | |
def value: Double | |
override val compute = BigDecimal.decimal(value, MathContext.DECIMAL64) | |
override val show = s"${value.toString}$currency" | |
def +(rhs: Amount[T]) = Add(this, rhs) | |
def -(rhs: Amount[T]) = Subtract(this, rhs) | |
def *(rhs: Coefficient) = MultiplyL(this, rhs) | |
def /(rhs: Coefficient) = Divide(this, rhs) | |
} | |
case class Coefficient(value: BigDecimal) extends Constant { | |
override val compute = value | |
override val show = value.toString | |
def *[T](rhs: ConstantAmount[T]) = MultiplyR(this, rhs) | |
} | |
sealed abstract class Operation[T](action: (BigDecimal, BigDecimal) => BigDecimal, symbol: String) extends Amount[T] { | |
def lhs: Expression | |
def rhs: Expression | |
override def compute = action(lhs.compute, rhs.compute) | |
override def show = (lhs, rhs) match { | |
case (_: Constant, _: Constant) => | |
s"${lhs.show} $symbol ${rhs.show}" | |
case (_: Operation[T], _: Constant) => | |
s"(${lhs.show}) $symbol ${rhs.show}" | |
case (_: Constant, _: Operation[T]) => | |
s"${lhs.show} $symbol (${rhs.show})" | |
case (_: Operation[T], _: Operation[T]) => | |
s"(${lhs.show}) $symbol (${rhs.show})" | |
} | |
} | |
case class Add[T](lhs: Amount[T], rhs: Amount[T]) extends Operation[T](_ + _, "+") | |
case class Subtract[T](lhs: Amount[T], rhs: Amount[T]) extends Operation[T](_ - _, "-") | |
case class MultiplyL[T](lhs: Amount[T], rhs: Coefficient) extends Operation[T](_ * _, "*") | |
case class MultiplyR[T](lhs: Coefficient, rhs: Amount[T]) extends Operation[T](_ * _, "*") | |
case class Divide[T](lhs: Amount[T], rhs: Coefficient) extends Operation[T](_ / _, "/") | |
case class Dollars(value: Double) extends ConstantAmount[Dollars]("$") | |
case class Yuan(value: Double) extends ConstantAmount[Yuan]("¥") | |
case class Pound(value: Double) extends ConstantAmount[Pound]("£") | |
object MathSyntax { | |
implicit def doubleToConstant(value: Double): Coefficient = Coefficient(BigDecimal.decimal(value, MathContext.DECIMAL64)) | |
} | |
object Main extends App { | |
import MathSyntax._ | |
val operation = Dollars(12.43) + (Dollars(54.62) * 4.55) | |
println(s"${operation.show} = ${operation.compute}") | |
// these will not compile | |
val compilationError1 = Dollars(12.43) / Dollars(43.32) | |
val compilationError2 = (Dollars(12.43) / 1.01) + (Pound(54.12) * 1.25) | |
val compilationError3 = Dollars(12.43) + Yuan(43.32) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment