/
Digit.scala
153 lines (113 loc) · 4.31 KB
/
Digit.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package scalaz
/**An algebraic data type representing the digits 0 - 9 */
sealed abstract class Digit extends Product with Serializable {
val toInt: Int
final def toLong: Long = toInt.toLong
final def toChar: Char = (toLong + 48).toChar
}
object Digit extends DigitInstances {
case object _0 extends Digit {
override val toInt = 0
}
case object _1 extends Digit {
override val toInt = 1
}
case object _2 extends Digit {
override val toInt = 2
}
case object _3 extends Digit {
override val toInt = 3
}
case object _4 extends Digit {
override val toInt = 4
}
case object _5 extends Digit {
override val toInt = 5
}
case object _6 extends Digit {
override val toInt = 6
}
case object _7 extends Digit {
override val toInt = 7
}
case object _8 extends Digit {
override val toInt = 8
}
case object _9 extends Digit {
override val toInt = 9
}
private val digitsArray: Array[Digit] = Array(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9)
val digits: IList[Digit] = IList(digitsArray : _*)
implicit def DigitLong(d: Digit): Long = d.toLong
def digitFromChar(c: Char): Option[Digit] = digitFromInt(c.toInt - 48)
def digitFromInt(i: Int): Option[Digit] =
if (0 <= i && i <= 9) Some(digitsArray(i)) else None
def digitFromLong(i: Long): Option[Digit] =
if (0L <= i && i <= 9L) Some(digitsArray(i.toInt)) else None
def digitsFromInt(i: Int): NonEmptyList[Digit] = digitsFromNumberString(i.toString)
def digitsFromLong(l: Long): NonEmptyList[Digit] = digitsFromNumberString(l.toString)
def digitsFromBigInt(b: BigInt): NonEmptyList[Digit] = digitsFromNumberString(b.toString)
private def digitsFromNumberString(number: String): NonEmptyList[Digit] = {
val (head, tail) = number.stripPrefix("-").splitAt(1)
NonEmptyList.nel(
digitsArray(head.charAt(0).toInt - 48), tail.foldRight(IList.empty[Digit]) ((c, ds) => digitsArray(c.toInt - 48) :: ds))
}
def mod10Digit(i: Int): Digit = digitsArray(scala.math.abs(i % 10))
def longDigits[F[_]](digits: F[Digit])(implicit F: Foldable[F]): Long =
F.foldLeft(digits, 0L)((n, a) => n * 10L + (a: Digit))
def digits[F[_]](cs: F[Char])(implicit F: Functor[F]): OptionT[F, Digit] =
OptionT(F.map(cs)(digitFromChar))
def digitsOr[F[_]](chars: F[Char], d: => Digit)(implicit F: Functor[F]): F[Digit] =
F.map(chars)(a => digitFromChar(a) getOrElse d)
def digitsCollapse[F[_]](chars: F[Char])(implicit F: MonadPlus[F]): F[Digit] =
F.bind(chars)(a => Digit.digitFromChar(a) match {
case None => F.empty[Digit]
case Some(d) => F.point(d)
})
def traverseDigits[F[_]](chars: F[Char])(implicit F: Traverse[F]): Option[F[Digit]] = {
import std.option._
F.sequence(digits(chars).run)
}
def traverseDigitsOr[F[_]](chars: F[Char], d: => F[Digit])(implicit F: Traverse[F]): F[Digit] =
traverseDigits(chars) getOrElse d
}
sealed abstract class DigitInstances {
implicit val digitInstances: Enum[Digit] with Show[Digit] with Monoid[Digit] = new Enum[Digit] with Show[Digit] with Monoid[Digit] {
import std.anyVal._
def succ(d: Digit) = d match {
case Digit._0 => Digit._1
case Digit._1 => Digit._2
case Digit._2 => Digit._3
case Digit._3 => Digit._4
case Digit._4 => Digit._5
case Digit._5 => Digit._6
case Digit._6 => Digit._7
case Digit._7 => Digit._8
case Digit._8 => Digit._9
case Digit._9 => Digit._0
}
def pred(d: Digit) = d match {
case Digit._0 => Digit._9
case Digit._1 => Digit._0
case Digit._2 => Digit._1
case Digit._3 => Digit._2
case Digit._4 => Digit._3
case Digit._5 => Digit._4
case Digit._6 => Digit._5
case Digit._7 => Digit._6
case Digit._8 => Digit._7
case Digit._9 => Digit._8
}
override def succn(n: Int, a: Digit) =
super.succn(n % 10, a)
override def predn(n: Int, a: Digit) =
super.predn(n % 10, a)
override def min = Some(Digit._0)
override def max = Some(Digit._9)
override def shows(f: Digit) = f.toChar.toString
def order(x: Digit, y: Digit): Ordering = Order[Int].order(x.toInt, y.toInt)
override def equal(x: Digit, y: Digit): Boolean = x == y
def append(f1: Digit, f2: => Digit): Digit = Digit.mod10Digit(f1.toInt + f2.toInt)
def zero: Digit = Digit._0
}
}