Guest User

Untitled

a guest
Dec 10th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.75 KB | None | 0 0
  1. sealed trait Nat
  2. trait Zero extends Nat
  3. trait Succ[N <: Nat] extends Nat
  4.  
  5. type Nat1 = Succ[Zero]
  6. type Nat2 = Succ[Nat1]
  7. type Nat3 = Succ[Nat2]
  8. type Nat4 = Succ[Nat3]
  9. type Nat5 = Succ[Nat4]
  10.  
  11. sealed trait ToInt[N <: Nat] { def value: Int }
  12. object ToInt {
  13. def apply[N <: Nat](implicit T: ToInt[N]): ToInt[N] = T
  14.  
  15. implicit val zeroToInt: ToInt[Zero] = new ToInt[Zero] { def value: Int = 0 }
  16. implicit def succToInt[N <: Nat](implicit T: ToInt[N]): ToInt[Succ[N]] =
  17. new ToInt[Succ[N]] { def value: Int = T.value + 1 }
  18. }
  19.  
  20. sealed trait Sum[A <: Nat, B <: Nat] { type Out <: Nat }
  21. object Sum {
  22. def apply[A <: Nat, B <: Nat](implicit S: Sum[A, B]): Aux[A, B, S.Out] = S
  23. type Aux[A <: Nat, B <: Nat, C <: Nat] = Sum[A, B] { type Out = C }
  24. implicit def sumZero[B <: Nat]: Aux[Zero, B, B] = new Sum[Zero, B] { type Out = B }
  25. 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 }
  26. }
  27.  
  28. sealed trait Diff[A <: Nat, B <: Nat] { type Out <: Nat }
  29. object Diff {
  30. def apply[A <: Nat, B <: Nat](implicit D: Diff[A, B]): Aux[A, B, D.Out] = D
  31. type Aux[A <: Nat, B <: Nat, C <: Nat] = Diff[A, B] { type Out = C }
  32. implicit def diffZero[A <: Nat]: Aux[A, Zero, A] = new Diff[A, Zero] { type Out = A }
  33. 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 }
  34. }
  35.  
  36. sealed trait Divisible[D <: Nat, N <: Nat]
  37. object Divisible {
  38. def apply[D <: Nat, N <: Nat](implicit D: Divisible[D, N]): Divisible[D, N] = D
  39.  
  40. implicit def zeroDiv[D <: Succ[_]]: Divisible[D, Zero] = new Divisible[D, Zero] {}
  41. implicit def succDiv[D <: Succ[_], N <: Nat, Diff <: Nat](implicit diff: Diff.Aux[N, D, Diff], D: Divisible[D, Diff]): Divisible[D, N] =
  42. new Divisible[D, N] {}
  43. }
  44.  
  45. sealed trait And[A, B]
  46. object And {
  47. implicit def and[A, B](implicit ev1: A, ev2: B): And[A ,B] = new And[A, B] {}
  48. }
  49.  
  50. sealed trait FizzBuzz[N <: Nat] {
  51.  
  52. def out: String
  53. println(out)
  54.  
  55. }
  56. trait OtherNat {
  57. implicit def otherwise[N <: Nat](implicit T: ToInt[N]): FizzBuzz[N] =
  58. new FizzBuzz[N] { override def out = s"${T.value}" }
  59. }
  60. trait IfDivisible3Or5 extends OtherNat {
  61.  
  62. implicit def divisible3[N <: Nat](implicit D: Divisible[Nat3, N]): FizzBuzz[N] =
  63. new FizzBuzz[N] { override def out: String = "Fizz" }
  64.  
  65. implicit def divisible5[N <: Nat](implicit D: Divisible[Nat5, N]): FizzBuzz[N] =
  66. new FizzBuzz[N] { override def out: String = "Buzz" }
  67.  
  68. }
  69.  
  70. object FizzBuzz extends IfDivisible3Or5 {
  71.  
  72. def apply[N <: Nat](implicit F: FizzBuzz[N]): FizzBuzz[N] = F
  73.  
  74. implicit def divisible3And5[N <: Nat](implicit A: Divisible[Nat3, N] And Divisible[Nat5, N]): FizzBuzz[N] =
  75. new FizzBuzz[N] { override def out: String = "FizzBuzz" }
  76.  
  77. }
  78.  
  79. sealed trait Prod[A <: Nat, B <: Nat] {
  80. type Out <: Nat
  81. }
  82. object Prod {
  83. def apply[A <: Nat, B <: Nat](implicit P: Prod[A, B]): Aux[A, B, P.Out] = P
  84. type Aux[A <: Nat, B <: Nat, C <: Nat] = Prod[A, B] { type Out = C }
  85. implicit def prod1[B <: Nat]: Aux[Zero, B, Zero] = new Prod[Zero, B] { type Out = Zero }
  86. 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] =
  87. new Prod[Succ[A], B] { type Out = D }
  88. }
  89.  
  90. sealed trait Range[E[_ <: Nat], A <: Nat, B <: Nat]
  91. object Range {
  92.  
  93. def apply[E[_ <: Nat], A <: Nat, B <: Nat](implicit R: Range[E, A, B]): Range[E, A, B] = R
  94.  
  95. implicit def equal[E[_ <: Nat], N <: Nat](implicit E: E[N]): Range[E, N, N] = new Range[E, N, N] {}
  96. 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]] {}
  97.  
  98. }
  99.  
  100. val nat10 = Prod[Nat2, Nat5]
  101. type Nat10 = nat10.Out
  102.  
  103. val nat100 = Prod[Nat10, Nat10]
  104. type Nat100 = nat100.Out
  105.  
  106. Range[FizzBuzz, Nat1, Nat100]
Add Comment
Please, Sign In to add comment