Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- sealed trait Nat
- trait Zero extends Nat
- trait Succ[N <: Nat] extends Nat
- type Nat1 = Succ[Zero]
- type Nat2 = Succ[Nat1]
- type Nat3 = Succ[Nat2]
- type Nat4 = Succ[Nat3]
- type Nat5 = Succ[Nat4]
- sealed trait ToInt[N <: Nat] { def value: Int }
- object ToInt {
- def apply[N <: Nat](implicit T: ToInt[N]): ToInt[N] = T
- implicit val zeroToInt: ToInt[Zero] = new ToInt[Zero] { def value: Int = 0 }
- implicit def succToInt[N <: Nat](implicit T: ToInt[N]): ToInt[Succ[N]] =
- new ToInt[Succ[N]] { def value: Int = T.value + 1 }
- }
- sealed trait Sum[A <: Nat, B <: Nat] { type Out <: Nat }
- object Sum {
- def apply[A <: Nat, B <: Nat](implicit S: Sum[A, B]): Aux[A, B, S.Out] = S
- type Aux[A <: Nat, B <: Nat, C <: Nat] = Sum[A, B] { type Out = C }
- implicit def sumZero[B <: Nat]: Aux[Zero, B, B] = new Sum[Zero, B] { type Out = B }
- implicit def sum[A <: Nat, B <: Nat, C <: Nat](implicit S: Aux[A, Succ[B], C]): Aux[Succ[A], B, C] = new Sum[Succ[A], B] { type Out = C }
- }
- sealed trait Diff[A <: Nat, B <: Nat] { type Out <: Nat }
- object Diff {
- def apply[A <: Nat, B <: Nat](implicit D: Diff[A, B]): Aux[A, B, D.Out] = D
- type Aux[A <: Nat, B <: Nat, C <: Nat] = Diff[A, B] { type Out = C }
- implicit def diffZero[A <: Nat]: Aux[A, Zero, A] = new Diff[A, Zero] { type Out = A }
- implicit def diff[A <: Nat, B <: Nat, C <: Nat](implicit D: Aux[A, B, C]): Aux[Succ[A], Succ[B], C] = new Diff[Succ[A], Succ[B]] { type Out = C }
- }
- sealed trait Divisible[D <: Nat, N <: Nat]
- object Divisible {
- def apply[D <: Nat, N <: Nat](implicit D: Divisible[D, N]): Divisible[D, N] = D
- implicit def zeroDiv[D <: Succ[_]]: Divisible[D, Zero] = new Divisible[D, Zero] {}
- implicit def succDiv[D <: Succ[_], N <: Nat, Diff <: Nat](implicit diff: Diff.Aux[N, D, Diff], D: Divisible[D, Diff]): Divisible[D, N] =
- new Divisible[D, N] {}
- }
- sealed trait And[A, B]
- object And {
- implicit def and[A, B](implicit ev1: A, ev2: B): And[A ,B] = new And[A, B] {}
- }
- sealed trait FizzBuzz[N <: Nat] {
- def out: String
- println(out)
- }
- trait OtherNat {
- implicit def otherwise[N <: Nat](implicit T: ToInt[N]): FizzBuzz[N] =
- new FizzBuzz[N] { override def out = s"${T.value}" }
- }
- trait IfDivisible3Or5 extends OtherNat {
- implicit def divisible3[N <: Nat](implicit D: Divisible[Nat3, N]): FizzBuzz[N] =
- new FizzBuzz[N] { override def out: String = "Fizz" }
- implicit def divisible5[N <: Nat](implicit D: Divisible[Nat5, N]): FizzBuzz[N] =
- new FizzBuzz[N] { override def out: String = "Buzz" }
- }
- object FizzBuzz extends IfDivisible3Or5 {
- def apply[N <: Nat](implicit F: FizzBuzz[N]): FizzBuzz[N] = F
- implicit def divisible3And5[N <: Nat](implicit A: Divisible[Nat3, N] And Divisible[Nat5, N]): FizzBuzz[N] =
- new FizzBuzz[N] { override def out: String = "FizzBuzz" }
- }
- sealed trait Prod[A <: Nat, B <: Nat] {
- type Out <: Nat
- }
- object Prod {
- def apply[A <: Nat, B <: Nat](implicit P: Prod[A, B]): Aux[A, B, P.Out] = P
- type Aux[A <: Nat, B <: Nat, C <: Nat] = Prod[A, B] { type Out = C }
- implicit def prod1[B <: Nat]: Aux[Zero, B, Zero] = new Prod[Zero, B] { type Out = Zero }
- implicit def prod2[A <: Nat, B <: Nat, C <: Nat, D <: Nat](implicit P: Prod.Aux[A, B, C], sum: Sum.Aux[B, C, D]): Aux[Succ[A], B, D] =
- new Prod[Succ[A], B] { type Out = D }
- }
- sealed trait Range[E[_ <: Nat], A <: Nat, B <: Nat]
- object Range {
- def apply[E[_ <: Nat], A <: Nat, B <: Nat](implicit R: Range[E, A, B]): Range[E, A, B] = R
- implicit def equal[E[_ <: Nat], N <: Nat](implicit E: E[N]): Range[E, N, N] = new Range[E, N, N] {}
- implicit def range[E[_ <: Nat], A <: Nat, B <: Nat](implicit R: Range[E, A, B], E: E[Succ[B]]): Range[E, A, Succ[B]] = new Range[E, A, Succ[B]] {}
- }
- val nat10 = Prod[Nat2, Nat5]
- type Nat10 = nat10.Out
- val nat100 = Prod[Nat10, Nat10]
- type Nat100 = nat100.Out
- Range[FizzBuzz, Nat1, Nat100]
Add Comment
Please, Sign In to add comment