Last active
August 29, 2015 14:21
-
-
Save dylemma/42630a183b604ca72029 to your computer and use it in GitHub Desktop.
Numbers represented as types in scala. Because you can.
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
| /** You can represent numbers as types. Why? Because you can! | |
| */ | |
| object TypesafeNumbers extends App { | |
| println(Number[E2[`2`] + E1[`4`] + `6`]) | |
| println(Number[`8` ~ `6` ~ `7` ~ `5` ~ `3` ~ `0` ~ `9`]) | |
| } | |
| // raw digits | |
| trait `0` | |
| trait `1` | |
| trait `2` | |
| trait `3` | |
| trait `4` | |
| trait `5` | |
| trait `6` | |
| trait `7` | |
| trait `8` | |
| trait `9` | |
| // type for numbers times a power of 10 | |
| class E1[D: Number] | |
| class E2[D: Number] | |
| // type for the sum of two numbers | |
| class +[Left: Number, Right: Number] | |
| // type for (Left*10) + Right | |
| class ~[Left: Number, Right: Number] | |
| // typeclass for getting the value of a number type | |
| trait Number[T] extends Any { def value: Int } | |
| // just a helper for the values of digits | |
| class RawNumber[T](val value: Int) extends AnyVal with Number[T] | |
| object Number { | |
| implicit def `0value` = new RawNumber[`0`](0) | |
| implicit def `1value` = new RawNumber[`1`](1) | |
| implicit def `2value` = new RawNumber[`2`](2) | |
| implicit def `3value` = new RawNumber[`3`](3) | |
| implicit def `4value` = new RawNumber[`4`](4) | |
| implicit def `5value` = new RawNumber[`5`](5) | |
| implicit def `6value` = new RawNumber[`6`](6) | |
| implicit def `7value` = new RawNumber[`7`](7) | |
| implicit def `8value` = new RawNumber[`8`](8) | |
| implicit def `9value` = new RawNumber[`9`](9) | |
| implicit def e1value[T: Number]: Number[E1[T]] = new Number[E1[T]] { | |
| def value: Int = implicitly[Number[T]].value * 10 | |
| } | |
| implicit def e2value[T: Number] = new Number[E2[T]] { | |
| def value = implicitly[Number[T]].value * 100 | |
| } | |
| // +[A, B] == A + B | |
| implicit def `+value`[A: Number, B: Number] = new Number[A + B] { | |
| def value = implicitly[Number[A]].value + implicitly[Number[B]].value | |
| } | |
| implicit def `~value`[A: Number, B: Number] = new Number[A ~ B] { | |
| def value = implicitly[Number[A]].value * 10 + implicitly[Number[B]].value | |
| } | |
| // lets you do `Number[some number type]` to get an Int | |
| def apply[N: Number] = implicitly[Number[N]].value | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment