Last active
January 12, 2017 06:00
-
-
Save piyo7/1eb5d254933ec57f6d42af0d2ea99853 to your computer and use it in GitHub Desktop.
おてがる単位型パターン 〜不正な単位演算はコンパイルエラーにしよう〜 ref: http://qiita.com/piyo7/items/df002e4fa9ec832ea0a2
This file contains hidden or 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
val imp: Int = 400 | |
val yen: Int = 30 | |
val cpm: Double = yen / imp |
This file contains hidden or 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
val imp: Int = 500 | |
val yen: Int = 30 | |
val cpm: Double = yen.toDouble / imp.toDouble * 1000 |
This file contains hidden or 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
val imp: Vimp = Vimp(400) | |
val yen: Yen = Yen(30) | |
val cpm: Cpm = yen / imp // コンパイルエラー!!! |
This file contains hidden or 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
val imp: Imp = Imp(500) | |
val yen: Yen = Yen(30) | |
val cpm: Cpm = yen.mapDouble / imp.mapDouble | |
assert(cpm == Cpm(60.0)) |
This file contains hidden or 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
implicit val mulImpCpmYen = UnitNum.Mul[Double, ImpTag, CpmTag, YenTag](0.001) |
This file contains hidden or 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
def *[Tag1, Tag2](x: UnitNum[A, Tag1])(implicit op: Numeric[A], mul: UnitNum.Mul[A, Tag, Tag1, Tag2]) = | |
UnitNum[A, Tag2](op.times(op.times(value, x.value), mul.factor)) | |
def /[Tag1, Tag2](x: UnitNum[A, Tag1])(implicit op: Fractional[A], mul: UnitNum.Mul[A, Tag1, Tag2, Tag]) = | |
UnitNum[A, Tag2](op.div(op.div(value, x.value), mul.factor)) |
This file contains hidden or 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
object Mul { | |
implicit def commutative[A, Tag1, Tag2, Tag3](implicit mul: Mul[A, Tag1, Tag2, Tag3]) = | |
Mul[A, Tag2, Tag1, Tag3](mul.factor) | |
} | |
} |
This file contains hidden or 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
$ scala -version | |
Scala code runner version 2.11.8 -- Copyright 2002-2016, LAMP/EPFL |
This file contains hidden or 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
case class UnitBase[A, Tag](value: A) extends AnyVal |
This file contains hidden or 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
def calcCpm(imp: Imp, yen: Yen): Cpm = | |
Cpm(yen.value.toDouble / imp.value.toDouble * 1000) |
This file contains hidden or 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
trait CpmTag | |
type Cpm = UnitBase[Double, CpmTag] | |
object Cpm { | |
def apply(value: Double) = new Cpm(value) | |
} |
This file contains hidden or 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
trait Numeric[T] extends Ordering[T] { | |
def plus(x: T, y: T): T | |
def minus(x: T, y: T): T | |
def times(x: T, y: T): T |
This file contains hidden or 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
trait Integral[T] extends Numeric[T] { |
This file contains hidden or 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
trait IntIsIntegral extends Integral[Int] { | |
def plus(x: Int, y: Int): Int = x + y | |
def minus(x: Int, y: Int): Int = x - y | |
def times(x: Int, y: Int): Int = x * y |
This file contains hidden or 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
implicit object IntIsIntegral extends IntIsIntegral with Ordering.IntOrdering |
This file contains hidden or 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
case class UnitNum[A, Tag](value: A) extends AnyVal { | |
def +(x: UnitNum[A, Tag])(implicit op: Numeric[A]) = | |
UnitNum[A, Tag](op.plus(value, x.value)) | |
def -(x: UnitNum[A, Tag])(implicit op: Numeric[A]) = | |
UnitNum[A, Tag](op.minus(value, x.value)) | |
def *[Tag1, Tag2](x: UnitNum[A, Tag1])(implicit op: Numeric[A], mul: UnitNum.Mul[A, Tag, Tag1, Tag2]) = | |
UnitNum[A, Tag2](op.times(op.times(value, x.value), mul.factor)) | |
def /[Tag1, Tag2](x: UnitNum[A, Tag1])(implicit op: Fractional[A], mul: UnitNum.Mul[A, Tag1, Tag2, Tag]) = | |
UnitNum[A, Tag2](op.div(op.div(value, x.value), mul.factor)) | |
def map[B](f: A => B) = | |
UnitNum[B, Tag](f(value)) | |
def unary_-(implicit op: Numeric[A]) = | |
map(op.negate) | |
def abs(implicit op: Numeric[A]) = | |
map(op.abs) | |
def mapInt(implicit op: Numeric[A]) = | |
map(op.toInt) | |
def mapLong(implicit op: Numeric[A]) = | |
map(op.toLong) | |
def mapFloat(implicit op: Numeric[A]) = | |
map(op.toFloat) | |
def mapDouble(implicit op: Numeric[A]) = | |
map(op.toDouble) | |
} | |
object UnitNum { | |
import scala.language.implicitConversions | |
implicit def ordering[A: Ordering, Tag]: Ordering[UnitNum[A, Tag]] = | |
Ordering.by(_.value) | |
implicit def ordered[A: Ordering, Tag](x: UnitNum[A, Tag]): Ordered[UnitNum[A, Tag]] = | |
Ordered.orderingToOrdered(x)(ordering[A, Tag]) | |
case class Mul[A, Tag1, Tag2, Tag3](factor: A) extends AnyVal | |
object Mul { | |
implicit def commutative[A, Tag1, Tag2, Tag3](implicit mul: Mul[A, Tag1, Tag2, Tag3]) = | |
Mul[A, Tag2, Tag1, Tag3](mul.factor) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment