From d1df57a514c0ede72569d21fcb00c24a2e173bfc Mon Sep 17 00:00:00 2001 From: Erik Erlandson Date: Tue, 9 Jun 2020 09:45:06 -0700 Subject: [PATCH 1/5] copy Fraction code into Fraction.scala wholesale --- .../scala/singleton/ops/impl/Fraction.scala | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 src/main/scala/singleton/ops/impl/Fraction.scala diff --git a/src/main/scala/singleton/ops/impl/Fraction.scala b/src/main/scala/singleton/ops/impl/Fraction.scala new file mode 100644 index 00000000..260f1f62 --- /dev/null +++ b/src/main/scala/singleton/ops/impl/Fraction.scala @@ -0,0 +1,196 @@ +package singleton.ops.impl + +import singleton.ops._ + +/** Represents a fraction + * + * @tparam N the numerator + * @tparam D the denominator + */ +trait Fraction[N <: XInt, D <: XInt] + +object Fraction { + + /** Typeclass for finding the greatest common divisor of two numbers using Euclid's algorithm. + * + * @tparam A a non-zero natural number + * @tparam B another non-zero natural number + */ + trait GCD[A <: XInt, B <: XInt] { + type Out <: XInt + } + + object GCD { + type Aux[A <: XInt, B <: XInt, Out0 <: XInt] = GCD[A, B] { type Out = Out0 } + + implicit def fractionBaseGCD[A <: XInt, B <: XInt, Rem <: XInt]( + implicit ev0: Require[A >= B], + ev1: OpInt.Aux[A % B, Rem], + ev2: Require[Rem == W.`0`.T]): Aux[A, B, B] = new GCD[A, B] { + type Out = B + } + + implicit def fractionRecurseGCD[A <: XInt, + B <: XInt, + Rem <: XInt, + D <: XInt]( + implicit ev0: Require[A >= B], + ev1: OpInt.Aux[A % B, Rem], + ev2: Require[Rem != W.`0`.T], + ev3: Aux[B, Rem, D]): Aux[A, B, D] = new GCD[A, B] { + type Out = D + } + + implicit def fractionRecurseGCD1[A <: XInt, + B <: XInt, + Rem <: XInt, + D <: XInt]( + implicit ev0: Require[B < A], + ev1: Aux[A, B, D]): Aux[B, A, D] = new GCD[B, A] { + type Out = D + } + } + + /** Typeclass for negating a fraction */ + trait Negate[F <: Fraction[_, _]] { + type Out <: Fraction[_, _] + } + + object Negate { + type Aux[F <: Fraction[_, _], Out0 <: Fraction[_, _]] = Negate[F] { + type Out = Out0 + } + + implicit def fractionNegate[N <: XInt, D <: XInt, NN <: XInt]( + implicit ev: OpInt.Aux[W.`0`.T - N, NN] + ): Aux[Fraction[N, D], Fraction[NN, D]] = new Negate[Fraction[N, D]] { + type Out = Fraction[NN, D] + } + } + + /** Typeclass to simplify a fraction */ + trait Simplify[F <: Fraction[_, _]] { + type Out <: Fraction[_, _] + } + + object Simplify { + type Aux[F <: Fraction[_, _], Out0 <: Fraction[_, _]] = Simplify[F] { + type Out = Out0 + } + + implicit def fractionSimplifyPositive[N <: XInt, + D <: XInt, + C <: XInt, + SN <: XInt, + SD <: XInt]( + implicit ev0: Require[N > W.`0`.T], + gcd: GCD.Aux[N, D, C], + n: OpInt.Aux[N / C, SN], + d: OpInt.Aux[D / C, SD] + ): Aux[Fraction[N, D], Fraction[SN, SD]] = new Simplify[Fraction[N, D]] { + type Out = Fraction[SN, SD] + } + + implicit def fractionSimplifyNegative[N <: XInt, + D <: XInt, + F <: Fraction[_, _], + SNF <: Fraction[_, _], + SF <: Fraction[_, _]]( + implicit ev: Require[N < W.`0`.T], + ev1: Negate.Aux[Fraction[N, D], F], + ev2: Aux[F, SNF], + ev3: Negate.Aux[SNF, SF]): Aux[Fraction[N, D], SF] = + new Simplify[Fraction[N, D]] { + type Out = SF + } + + implicit def fractionSimplifyZero[D <: XInt] + : Aux[Fraction[W.`0`.T, D], Fraction[W.`0`.T, D]] = new Simplify[Fraction[W.`0`.T, D]] { + type Out = Fraction[W.`0`.T, D] + } + } + + /** Typeclass to add two fractions */ + trait Add[L <: Fraction[_, _], R <: Fraction[_, _]] { + type Out <: Fraction[_, _] + } + + object Add { + type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] = + Add[L, R] { type Out = Out0 } + + implicit def fractionAdd[LN <: XInt, + LD <: XInt, + RN <: XInt, + RD <: XInt, + LNRD <: XInt, + RNLD <: XInt, + N <: XInt, + D <: XInt, + F <: Fraction[_, _]]( + implicit ev0: OpInt.Aux[LN * RD, LNRD], + ev1: OpInt.Aux[RN * LD, RNLD], + ev2: OpInt.Aux[LNRD + RNLD, N], + ev3: OpInt.Aux[LD * RD, D], + ev4: Simplify.Aux[Fraction[N, D], F] + ): Aux[Fraction[LN, LD], Fraction[RN, RD], F] = + new Add[Fraction[LN, LD], Fraction[RN, RD]] { + type Out = F + } + } + + /** Typeclass for subtracting fractions */ + trait Subtract[L <: Fraction[_, _], R <: Fraction[_, _]] { + type Out <: Fraction[_, _] + } + + object Subtract { + type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] = + Subtract[L, R] { type Out = Out0 } + + implicit def fractionSubtract[L <: Fraction[_, _], + R <: Fraction[_, _], + NR <: Fraction[_, _], + F <: Fraction[_, _]]( + implicit ev0: Negate.Aux[R, NR], + ev1: Add.Aux[L, NR, F] + ): Aux[L, R, F] = new Subtract[L, R] { + type Out = F + } + } + + /** Typeclass to multiply two fractions */ + trait Multiply[L <: Fraction[_, _], R <: Fraction[_, _]] { + type Out <: Fraction[_, _] + } + + object Multiply { + type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] = + Multiply[L, R] { type Out = Out0 } + + implicit def fractionMultiply[LN <: XInt, + LD <: XInt, + RN <: XInt, + RD <: XInt, + N <: XInt, + D <: XInt, + F <: Fraction[_, _]]( + implicit ev0: OpInt.Aux[LN * RN, N], + ev1: OpInt.Aux[LD * RD, D], + ev2: Simplify.Aux[Fraction[N, D], F] + ): Aux[Fraction[LN, LD], Fraction[RN, RD], F] = + new Multiply[Fraction[LN, LD], Fraction[RN, RD]] { + type Out = F + } + } + + /** Typeclass to determine if a fraction is non-zero and finite */ + trait Valid[F <: Fraction[_, _]] + + object Valid { + implicit def valid[FN <: XInt, FD <: XInt]( + implicit ev0: Require[FN != W.`0`.T], + ev1: Require[FD != W.`0`.T]): Valid[Fraction[FN, FD]] = + new Valid[Fraction[FN, FD]] {} + } +} From 979e441119e771c738b9e46102607e840ae83123 Mon Sep 17 00:00:00 2001 From: Erik Erlandson Date: Wed, 10 Jun 2020 10:08:32 -0700 Subject: [PATCH 2/5] Draft of Fraction Add / + (not working) --- .../scala/singleton/ops/impl/Fraction.scala | 31 +++++++++++++++++-- .../singleton/ops/impl/GeneralMacros.scala | 22 +++++++++++-- .../scala/singleton/ops/impl/OpMacros.scala | 21 +++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/main/scala/singleton/ops/impl/Fraction.scala b/src/main/scala/singleton/ops/impl/Fraction.scala index 260f1f62..7b7a29a3 100644 --- a/src/main/scala/singleton/ops/impl/Fraction.scala +++ b/src/main/scala/singleton/ops/impl/Fraction.scala @@ -7,10 +7,27 @@ import singleton.ops._ * @tparam N the numerator * @tparam D the denominator */ -trait Fraction[N <: XInt, D <: XInt] +trait Fraction[N <: XInt, D <: XInt] { + val n: Int + val d: Int + override def toString: String = s"Fraction($n, $d)" +} object Fraction { + // get the 'Out' type resulting from resolving an implicit type + object impeval { + trait Out[O] + def apply[I <: { type Out } ](implicit i: I): Out[i.Out] = new Out[i.Out] {} + } + + implicit def fracAddition[L <: Fraction[_, _], R <: Fraction[_, _], O <: Fraction[_, _]](implicit + add: Add.Aux[L, R, O]): OpIntercept.Aux[OpId.+, L, R, W.`0`.T, O] = + new OpIntercept[OpId.+, L, R, W.`0`.T] { + type Out = O + val value = add.value + } + /** Typeclass for finding the greatest common divisor of two numbers using Euclid's algorithm. * * @tparam A a non-zero natural number @@ -110,9 +127,17 @@ object Fraction { } } + implicit def instantiateFraction[N <: XInt, D <: XInt](implicit + nv: Id[N], + dv: Id[D]): Fraction[N, D] = new Fraction[N, D] { + val n = nv.value.asInstanceOf[Int] + val d = dv.value.asInstanceOf[Int] + } + /** Typeclass to add two fractions */ trait Add[L <: Fraction[_, _], R <: Fraction[_, _]] { type Out <: Fraction[_, _] + val value: Out } object Add { @@ -132,10 +157,12 @@ object Fraction { ev1: OpInt.Aux[RN * LD, RNLD], ev2: OpInt.Aux[LNRD + RNLD, N], ev3: OpInt.Aux[LD * RD, D], - ev4: Simplify.Aux[Fraction[N, D], F] + ev4: Simplify.Aux[Fraction[N, D], F], + f: F ): Aux[Fraction[LN, LD], Fraction[RN, RD], F] = new Add[Fraction[LN, LD], Fraction[RN, RD]] { type Out = F + val value = f } } diff --git a/src/main/scala/singleton/ops/impl/GeneralMacros.scala b/src/main/scala/singleton/ops/impl/GeneralMacros.scala index 6679139b..f9bde0ae 100644 --- a/src/main/scala/singleton/ops/impl/GeneralMacros.scala +++ b/src/main/scala/singleton/ops/impl/GeneralMacros.scala @@ -655,6 +655,13 @@ trait GeneralMacros { //////////////////////////////////////////////////////////////////////// def abort(msg: String, annotatedSym : Option[TypeSymbol] = defaultAnnotatedSym): Nothing = { + val st = java.lang.Thread.currentThread().getStackTrace() + println("\n\nstack trace:") + for { e <- st.filter(_.getClassName().startsWith("singleton")) } { + println(s" $e") + } + println("\n") + //java.lang.Thread.dumpStack() VerboseTraversal(s"!!!!!!aborted with: $msg at $annotatedSym, $defaultAnnotatedSym") if (annotatedSym.isDefined) setAnnotation(msg, annotatedSym.get) c.abort(c.enclosingPosition, msg) @@ -719,6 +726,7 @@ trait GeneralMacros { } def genOpTreeUnknown(opTpe : Type, calc : CalcUnknown) : Tree = { + println("In genOpTreeUnknown") val outTpe = calc.tpe calc.treeOption match { case Some(valueTree) => @@ -898,10 +906,17 @@ trait GeneralMacros { lazy val a = aCalc lazy val b = bCalc lazy val cArg = cCalc + def unsupported() : Calc = { - (a, b) match { - case (aArg : CalcVal, bArg : CalcVal) => abort(s"Unsupported $funcType[$a, $b, $cArg]") - case _ => CalcUnknown(funcType.toType, None) + val itree = c.typecheck(q"implicitly[_root_.singleton.ops.impl.OpIntercept[${funcType.toType}, ${a.tpe}, ${b.tpe}, ${cArg.tpe}]]", silent = true) + if (itree != EmptyTree) { + println(s"\n\nitree= ${itree.tpe}\n\n") + CalcUnknown(itree.tpe, Some(itree)) + } else { + (a, b) match { + case (aArg : CalcVal, bArg : CalcVal) => abort(s"Unsupported $funcType[$a, $b, $cArg]") + case _ => CalcUnknown(funcType.toType, None) + } } } @@ -1372,6 +1387,7 @@ trait GeneralMacros { final class MaterializeOpAuxGen(opTpe: Type) { def usingFuncName : Tree = { + println(s"usingFuncName: opTpe= $opTpe") val funcType = opTpe.typeArgs.head.typeSymbol.asType val opResult = TypeCalc(opTpe) diff --git a/src/main/scala/singleton/ops/impl/OpMacros.scala b/src/main/scala/singleton/ops/impl/OpMacros.scala index 3d8bb5c4..6a9c7413 100644 --- a/src/main/scala/singleton/ops/impl/OpMacros.scala +++ b/src/main/scala/singleton/ops/impl/OpMacros.scala @@ -1,6 +1,27 @@ package singleton.ops.impl import scala.reflect.macros.whitebox + +trait OpIntercept[N, S1, S2, S3] extends OpMacro[N, S2, S2, S3] { + import singleton.ops.W + + type OutWide = None.type + val valueWide: OutWide = None + val isLiteral: Boolean = false + type OutNat = shapeless.Nat._0 + type OutChar = W.`'0'`.T + type OutInt = W.`0`.T + type OutLong = W.`0L`.T + type OutFloat = W.`0f`.T + type OutDouble = W.`0D`.T + type OutString = W.`""`.T + type OutBoolean = W.`false`.T +} + +object OpIntercept { + type Aux[N, S1, S2, S3, O] = OpIntercept[N, S1, S2, S3] { type Out = O } +} + /******************************************************************************************************** * Three arguments type function macro *******************************************************************************************************/ From 8931ac1947dc53b2ab4246f4d3b4fbbb5a05e10f Mon Sep 17 00:00:00 2001 From: Erik Erlandson Date: Wed, 10 Jun 2020 14:58:37 -0700 Subject: [PATCH 3/5] make debugging output cleaner --- src/main/scala/singleton/ops/impl/GeneralMacros.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/singleton/ops/impl/GeneralMacros.scala b/src/main/scala/singleton/ops/impl/GeneralMacros.scala index f9bde0ae..b868aea3 100644 --- a/src/main/scala/singleton/ops/impl/GeneralMacros.scala +++ b/src/main/scala/singleton/ops/impl/GeneralMacros.scala @@ -1387,10 +1387,12 @@ trait GeneralMacros { final class MaterializeOpAuxGen(opTpe: Type) { def usingFuncName : Tree = { - println(s"usingFuncName: opTpe= $opTpe") val funcType = opTpe.typeArgs.head.typeSymbol.asType val opResult = TypeCalc(opTpe) + println(s"usingFuncName: opTpe= $opTpe") + println(s" funcType= $funcType") + println(s" opResult= $opResult") val genTree = (funcType, opResult) match { case (funcTypes.ToNat, CalcLit.Int(t)) => if (t < 0) abort(s"Nat cannot be a negative literal. Found: $t") From 40fdb71ecb4e44abb77cefd536347fd3a2e113d0 Mon Sep 17 00:00:00 2001 From: Erik Erlandson Date: Wed, 10 Jun 2020 15:44:50 -0700 Subject: [PATCH 4/5] TestRig --- .../scala/singleton/ops/impl/TestRig.scala | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/scala/singleton/ops/impl/TestRig.scala diff --git a/src/main/scala/singleton/ops/impl/TestRig.scala b/src/main/scala/singleton/ops/impl/TestRig.scala new file mode 100644 index 00000000..809c215e --- /dev/null +++ b/src/main/scala/singleton/ops/impl/TestRig.scala @@ -0,0 +1,39 @@ +package singleton.ops.impl + +import singleton.ops._ + +trait Rig[V <: XInt] { + val value: Int + override def toString: String = s"Rig($value)" +} + +object Rig { + // get the 'Out' type resulting from resolving an implicit type + object impeval { + trait Out[O] + def apply[I <: { type Out } ](implicit i: I): Out[i.Out] = new Out[i.Out] {} + } + + implicit def rigAddition[L <: Rig[_], R <: Rig[_], O <: Rig[_]](implicit + add: Add.Aux[L, R, O]): OpIntercept.Aux[OpId.+, L, R, W.`0`.T, O] = + new OpIntercept[OpId.+, L, R, W.`0`.T] { + type Out = O + val value = add.value + } + + trait Add[L, R] { + type Out + val value: Out + } + object Add { + type Aux[L, R, O] = Add[L, R] { type Out = O } + + implicit def addRig[LV <: XInt, RV <: XInt, OV <: XInt](implicit + add: OpInt.Aux[LV + RV, OV]): Add.Aux[Rig[LV], Rig[RV], Rig[OV]] = + new Add[Rig[LV], Rig[RV]] { + type Out = Rig[OV] + val value = new Rig[OV] { val value = add.value } + } + } +} + From 21f939a9464a3f87056b28c92f51fc5409e8aee1 Mon Sep 17 00:00:00 2001 From: Erik Erlandson Date: Wed, 10 Jun 2020 15:45:24 -0700 Subject: [PATCH 5/5] remove Fraction.scala for this PR --- .../scala/singleton/ops/impl/Fraction.scala | 223 ------------------ 1 file changed, 223 deletions(-) delete mode 100644 src/main/scala/singleton/ops/impl/Fraction.scala diff --git a/src/main/scala/singleton/ops/impl/Fraction.scala b/src/main/scala/singleton/ops/impl/Fraction.scala deleted file mode 100644 index 7b7a29a3..00000000 --- a/src/main/scala/singleton/ops/impl/Fraction.scala +++ /dev/null @@ -1,223 +0,0 @@ -package singleton.ops.impl - -import singleton.ops._ - -/** Represents a fraction - * - * @tparam N the numerator - * @tparam D the denominator - */ -trait Fraction[N <: XInt, D <: XInt] { - val n: Int - val d: Int - override def toString: String = s"Fraction($n, $d)" -} - -object Fraction { - - // get the 'Out' type resulting from resolving an implicit type - object impeval { - trait Out[O] - def apply[I <: { type Out } ](implicit i: I): Out[i.Out] = new Out[i.Out] {} - } - - implicit def fracAddition[L <: Fraction[_, _], R <: Fraction[_, _], O <: Fraction[_, _]](implicit - add: Add.Aux[L, R, O]): OpIntercept.Aux[OpId.+, L, R, W.`0`.T, O] = - new OpIntercept[OpId.+, L, R, W.`0`.T] { - type Out = O - val value = add.value - } - - /** Typeclass for finding the greatest common divisor of two numbers using Euclid's algorithm. - * - * @tparam A a non-zero natural number - * @tparam B another non-zero natural number - */ - trait GCD[A <: XInt, B <: XInt] { - type Out <: XInt - } - - object GCD { - type Aux[A <: XInt, B <: XInt, Out0 <: XInt] = GCD[A, B] { type Out = Out0 } - - implicit def fractionBaseGCD[A <: XInt, B <: XInt, Rem <: XInt]( - implicit ev0: Require[A >= B], - ev1: OpInt.Aux[A % B, Rem], - ev2: Require[Rem == W.`0`.T]): Aux[A, B, B] = new GCD[A, B] { - type Out = B - } - - implicit def fractionRecurseGCD[A <: XInt, - B <: XInt, - Rem <: XInt, - D <: XInt]( - implicit ev0: Require[A >= B], - ev1: OpInt.Aux[A % B, Rem], - ev2: Require[Rem != W.`0`.T], - ev3: Aux[B, Rem, D]): Aux[A, B, D] = new GCD[A, B] { - type Out = D - } - - implicit def fractionRecurseGCD1[A <: XInt, - B <: XInt, - Rem <: XInt, - D <: XInt]( - implicit ev0: Require[B < A], - ev1: Aux[A, B, D]): Aux[B, A, D] = new GCD[B, A] { - type Out = D - } - } - - /** Typeclass for negating a fraction */ - trait Negate[F <: Fraction[_, _]] { - type Out <: Fraction[_, _] - } - - object Negate { - type Aux[F <: Fraction[_, _], Out0 <: Fraction[_, _]] = Negate[F] { - type Out = Out0 - } - - implicit def fractionNegate[N <: XInt, D <: XInt, NN <: XInt]( - implicit ev: OpInt.Aux[W.`0`.T - N, NN] - ): Aux[Fraction[N, D], Fraction[NN, D]] = new Negate[Fraction[N, D]] { - type Out = Fraction[NN, D] - } - } - - /** Typeclass to simplify a fraction */ - trait Simplify[F <: Fraction[_, _]] { - type Out <: Fraction[_, _] - } - - object Simplify { - type Aux[F <: Fraction[_, _], Out0 <: Fraction[_, _]] = Simplify[F] { - type Out = Out0 - } - - implicit def fractionSimplifyPositive[N <: XInt, - D <: XInt, - C <: XInt, - SN <: XInt, - SD <: XInt]( - implicit ev0: Require[N > W.`0`.T], - gcd: GCD.Aux[N, D, C], - n: OpInt.Aux[N / C, SN], - d: OpInt.Aux[D / C, SD] - ): Aux[Fraction[N, D], Fraction[SN, SD]] = new Simplify[Fraction[N, D]] { - type Out = Fraction[SN, SD] - } - - implicit def fractionSimplifyNegative[N <: XInt, - D <: XInt, - F <: Fraction[_, _], - SNF <: Fraction[_, _], - SF <: Fraction[_, _]]( - implicit ev: Require[N < W.`0`.T], - ev1: Negate.Aux[Fraction[N, D], F], - ev2: Aux[F, SNF], - ev3: Negate.Aux[SNF, SF]): Aux[Fraction[N, D], SF] = - new Simplify[Fraction[N, D]] { - type Out = SF - } - - implicit def fractionSimplifyZero[D <: XInt] - : Aux[Fraction[W.`0`.T, D], Fraction[W.`0`.T, D]] = new Simplify[Fraction[W.`0`.T, D]] { - type Out = Fraction[W.`0`.T, D] - } - } - - implicit def instantiateFraction[N <: XInt, D <: XInt](implicit - nv: Id[N], - dv: Id[D]): Fraction[N, D] = new Fraction[N, D] { - val n = nv.value.asInstanceOf[Int] - val d = dv.value.asInstanceOf[Int] - } - - /** Typeclass to add two fractions */ - trait Add[L <: Fraction[_, _], R <: Fraction[_, _]] { - type Out <: Fraction[_, _] - val value: Out - } - - object Add { - type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] = - Add[L, R] { type Out = Out0 } - - implicit def fractionAdd[LN <: XInt, - LD <: XInt, - RN <: XInt, - RD <: XInt, - LNRD <: XInt, - RNLD <: XInt, - N <: XInt, - D <: XInt, - F <: Fraction[_, _]]( - implicit ev0: OpInt.Aux[LN * RD, LNRD], - ev1: OpInt.Aux[RN * LD, RNLD], - ev2: OpInt.Aux[LNRD + RNLD, N], - ev3: OpInt.Aux[LD * RD, D], - ev4: Simplify.Aux[Fraction[N, D], F], - f: F - ): Aux[Fraction[LN, LD], Fraction[RN, RD], F] = - new Add[Fraction[LN, LD], Fraction[RN, RD]] { - type Out = F - val value = f - } - } - - /** Typeclass for subtracting fractions */ - trait Subtract[L <: Fraction[_, _], R <: Fraction[_, _]] { - type Out <: Fraction[_, _] - } - - object Subtract { - type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] = - Subtract[L, R] { type Out = Out0 } - - implicit def fractionSubtract[L <: Fraction[_, _], - R <: Fraction[_, _], - NR <: Fraction[_, _], - F <: Fraction[_, _]]( - implicit ev0: Negate.Aux[R, NR], - ev1: Add.Aux[L, NR, F] - ): Aux[L, R, F] = new Subtract[L, R] { - type Out = F - } - } - - /** Typeclass to multiply two fractions */ - trait Multiply[L <: Fraction[_, _], R <: Fraction[_, _]] { - type Out <: Fraction[_, _] - } - - object Multiply { - type Aux[L <: Fraction[_, _], R <: Fraction[_, _], Out0 <: Fraction[_, _]] = - Multiply[L, R] { type Out = Out0 } - - implicit def fractionMultiply[LN <: XInt, - LD <: XInt, - RN <: XInt, - RD <: XInt, - N <: XInt, - D <: XInt, - F <: Fraction[_, _]]( - implicit ev0: OpInt.Aux[LN * RN, N], - ev1: OpInt.Aux[LD * RD, D], - ev2: Simplify.Aux[Fraction[N, D], F] - ): Aux[Fraction[LN, LD], Fraction[RN, RD], F] = - new Multiply[Fraction[LN, LD], Fraction[RN, RD]] { - type Out = F - } - } - - /** Typeclass to determine if a fraction is non-zero and finite */ - trait Valid[F <: Fraction[_, _]] - - object Valid { - implicit def valid[FN <: XInt, FD <: XInt]( - implicit ev0: Require[FN != W.`0`.T], - ev1: Require[FD != W.`0`.T]): Valid[Fraction[FN, FD]] = - new Valid[Fraction[FN, FD]] {} - } -}