Skip to content

Commit d1df57a

Browse files
committed
copy Fraction code into Fraction.scala wholesale
1 parent 2150800 commit d1df57a

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package singleton.ops.impl
2+
3+
import singleton.ops._
4+
5+
/** Represents a fraction
6+
*
7+
* @tparam N the numerator
8+
* @tparam D the denominator
9+
*/
10+
trait Fraction[N <: XInt, D <: XInt]
11+
12+
object Fraction {
13+
14+
/** Typeclass for finding the greatest common divisor of two numbers using Euclid's algorithm.
15+
*
16+
* @tparam A a non-zero natural number
17+
* @tparam B another non-zero natural number
18+
*/
19+
trait GCD[A <: XInt, B <: XInt] {
20+
type Out <: XInt
21+
}
22+
23+
object GCD {
24+
type Aux[A <: XInt, B <: XInt, Out0 <: XInt] = GCD[A, B] { type Out = Out0 }
25+
26+
implicit def fractionBaseGCD[A <: XInt, B <: XInt, Rem <: XInt](
27+
implicit ev0: Require[A >= B],
28+
ev1: OpInt.Aux[A % B, Rem],
29+
ev2: Require[Rem == W.`0`.T]): Aux[A, B, B] = new GCD[A, B] {
30+
type Out = B
31+
}
32+
33+
implicit def fractionRecurseGCD[A <: XInt,
34+
B <: XInt,
35+
Rem <: XInt,
36+
D <: XInt](
37+
implicit ev0: Require[A >= B],
38+
ev1: OpInt.Aux[A % B, Rem],
39+
ev2: Require[Rem != W.`0`.T],
40+
ev3: Aux[B, Rem, D]): Aux[A, B, D] = new GCD[A, B] {
41+
type Out = D
42+
}
43+
44+
implicit def fractionRecurseGCD1[A <: XInt,
45+
B <: XInt,
46+
Rem <: XInt,
47+
D <: XInt](
48+
implicit ev0: Require[B < A],
49+
ev1: Aux[A, B, D]): Aux[B, A, D] = new GCD[B, A] {
50+
type Out = D
51+
}
52+
}
53+
54+
/** Typeclass for negating a fraction */
55+
trait Negate[F <: Fraction[_, _]] {
56+
type Out <: Fraction[_, _]
57+
}
58+
59+
object Negate {
60+
type Aux[F <: Fraction[_, _], Out0 <: Fraction[_, _]] = Negate[F] {
61+
type Out = Out0
62+
}
63+
64+
implicit def fractionNegate[N <: XInt, D <: XInt, NN <: XInt](
65+
implicit ev: OpInt.Aux[W.`0`.T - N, NN]
66+
): Aux[Fraction[N, D], Fraction[NN, D]] = new Negate[Fraction[N, D]] {
67+
type Out = Fraction[NN, D]
68+
}
69+
}
70+
71+
/** Typeclass to simplify a fraction */
72+
trait Simplify[F <: Fraction[_, _]] {
73+
type Out <: Fraction[_, _]
74+
}
75+
76+
object Simplify {
77+
type Aux[F <: Fraction[_, _], Out0 <: Fraction[_, _]] = Simplify[F] {
78+
type Out = Out0
79+
}
80+
81+
implicit def fractionSimplifyPositive[N <: XInt,
82+
D <: XInt,
83+
C <: XInt,
84+
SN <: XInt,
85+
SD <: XInt](
86+
implicit ev0: Require[N > W.`0`.T],
87+
gcd: GCD.Aux[N, D, C],
88+
n: OpInt.Aux[N / C, SN],
89+
d: OpInt.Aux[D / C, SD]
90+
): Aux[Fraction[N, D], Fraction[SN, SD]] = new Simplify[Fraction[N, D]] {
91+
type Out = Fraction[SN, SD]
92+
}
93+
94+
implicit def fractionSimplifyNegative[N <: XInt,
95+
D <: XInt,
96+
F <: Fraction[_, _],
97+
SNF <: Fraction[_, _],
98+
SF <: Fraction[_, _]](
99+
implicit ev: Require[N < W.`0`.T],
100+
ev1: Negate.Aux[Fraction[N, D], F],
101+
ev2: Aux[F, SNF],
102+
ev3: Negate.Aux[SNF, SF]): Aux[Fraction[N, D], SF] =
103+
new Simplify[Fraction[N, D]] {
104+
type Out = SF
105+
}
106+
107+
implicit def fractionSimplifyZero[D <: XInt]
108+
: Aux[Fraction[W.`0`.T, D], Fraction[W.`0`.T, D]] = new Simplify[Fraction[W.`0`.T, D]] {
109+
type Out = Fraction[W.`0`.T, D]
110+
}
111+
}
112+
113+
/** Typeclass to add two fractions */
114+
trait Add[L <: Fraction[_, _], R <: Fraction[_, _]] {
115+
type Out <: Fraction[_, _]
116+
}
117+
118+
object Add {
119+
type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] =
120+
Add[L, R] { type Out = Out0 }
121+
122+
implicit def fractionAdd[LN <: XInt,
123+
LD <: XInt,
124+
RN <: XInt,
125+
RD <: XInt,
126+
LNRD <: XInt,
127+
RNLD <: XInt,
128+
N <: XInt,
129+
D <: XInt,
130+
F <: Fraction[_, _]](
131+
implicit ev0: OpInt.Aux[LN * RD, LNRD],
132+
ev1: OpInt.Aux[RN * LD, RNLD],
133+
ev2: OpInt.Aux[LNRD + RNLD, N],
134+
ev3: OpInt.Aux[LD * RD, D],
135+
ev4: Simplify.Aux[Fraction[N, D], F]
136+
): Aux[Fraction[LN, LD], Fraction[RN, RD], F] =
137+
new Add[Fraction[LN, LD], Fraction[RN, RD]] {
138+
type Out = F
139+
}
140+
}
141+
142+
/** Typeclass for subtracting fractions */
143+
trait Subtract[L <: Fraction[_, _], R <: Fraction[_, _]] {
144+
type Out <: Fraction[_, _]
145+
}
146+
147+
object Subtract {
148+
type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] =
149+
Subtract[L, R] { type Out = Out0 }
150+
151+
implicit def fractionSubtract[L <: Fraction[_, _],
152+
R <: Fraction[_, _],
153+
NR <: Fraction[_, _],
154+
F <: Fraction[_, _]](
155+
implicit ev0: Negate.Aux[R, NR],
156+
ev1: Add.Aux[L, NR, F]
157+
): Aux[L, R, F] = new Subtract[L, R] {
158+
type Out = F
159+
}
160+
}
161+
162+
/** Typeclass to multiply two fractions */
163+
trait Multiply[L <: Fraction[_, _], R <: Fraction[_, _]] {
164+
type Out <: Fraction[_, _]
165+
}
166+
167+
object Multiply {
168+
type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] =
169+
Multiply[L, R] { type Out = Out0 }
170+
171+
implicit def fractionMultiply[LN <: XInt,
172+
LD <: XInt,
173+
RN <: XInt,
174+
RD <: XInt,
175+
N <: XInt,
176+
D <: XInt,
177+
F <: Fraction[_, _]](
178+
implicit ev0: OpInt.Aux[LN * RN, N],
179+
ev1: OpInt.Aux[LD * RD, D],
180+
ev2: Simplify.Aux[Fraction[N, D], F]
181+
): Aux[Fraction[LN, LD], Fraction[RN, RD], F] =
182+
new Multiply[Fraction[LN, LD], Fraction[RN, RD]] {
183+
type Out = F
184+
}
185+
}
186+
187+
/** Typeclass to determine if a fraction is non-zero and finite */
188+
trait Valid[F <: Fraction[_, _]]
189+
190+
object Valid {
191+
implicit def valid[FN <: XInt, FD <: XInt](
192+
implicit ev0: Require[FN != W.`0`.T],
193+
ev1: Require[FD != W.`0`.T]): Valid[Fraction[FN, FD]] =
194+
new Valid[Fraction[FN, FD]] {}
195+
}
196+
}

0 commit comments

Comments
 (0)