Я хочу представить класс типов с номерами сравнения, такими как типы, но также и даты.
Вот мой класс типов:
trait NumberLike[A] {
def lessThenOrEqual[B](a: A, b: B): Boolean
def moreThenOrEqual[B](a: A, b: B): Boolean
}
object NumberLike {
def apply[A](implicit numericalLike: NumberLike[A]): NumberLike[A] =
numericalLike
def lessThenOrEqual[A: NumberLike, B](a: A)(b: B): Boolean =
NumberLike[A].lessThenOrEqual(a, b)
def moreThenOrEqual[A: NumberLike, B](a: A)(b: B): Boolean =
NumberLike[A].moreThenOrEqual(a, b)
def instance[A, B](
lTOE: (A, B) => Boolean,
mTOE: (A, B) => Boolean
): NumberLike[A] = new NumberLike[A] {
def lessThenOrEqual[B](a: A, b: B): Boolean = lTOE(a, b)
def moreThenOrEqual[B](a: A, b: B): Boolean = mTOE(a, b)
}
implicit class NumericalLikeOps[A: NumberLike](a: A) {
def lessThenOrEqual[B](b: B): Boolean = NumberLike[A].lessThenOrEqual(a, b)
def moreThenOrEqual[B](b: B): Boolean = NumberLike[A].moreThenOrEqual(a, b)
}
}
Проблема в том, что я хочу, чтобы у функции lessThenOrEqual (a, b) была возможность поставить другой тип, так как я сделаю сравнениемежду, например, целыми числами и числами с плавающей запятой. Тем не менее, класс типов будет только один для каждого типа, независимо, если я смогу привести, например, целые числа с более чем одним типом, скажем, целыми числами и числами с плавающей точкой. Таким образом, тип B является просто указанием функции и не должен быть переменной класса типа.
Для примера у меня будет проблема, что тип B не принимается как переменная функции.
Есть ли обходной путь для этого? Или, другими словами, как я могу сделать переменную B просто функционально-зависимой для lTOE в определении экземпляра?
РЕДАКТИРОВАТЬ:
Я использовалСледующее решение, предложенное решениями:
trait NumberLike[A] {
type B
def lessThenOrEqual(a: A, b: B): Boolean
def moreThenOrEqual(a: A, b: B): Boolean
}
object NumberLike {
type Aux[A, B0] = NumberLike[A] { type B = B0 }
def apply[A, B](implicit numberLike: Aux[A, B]): Aux[A, B] =
numberLike
def lessThenOrEqual[A, B](a: A)(b: B)(
implicit numberLike: Aux[A, B]): Boolean =
numberLike.lessThenOrEqual(a, b)
def moreThenOrEqual[A, B](a: A)(b: B)(
implicit numberLike: Aux[A, B]): Boolean =
numberLike.moreThenOrEqual(a, b)
def instance[A, B0](
lTOE: (A, B0) => Boolean,
mTOE: (A, B0) => Boolean
): Aux[A, B0] = new NumberLike[A] {
type B = B0
def lessThenOrEqual(a: A, b: B): Boolean = lTOE(a, b)
def moreThenOrEqual(a: A, b: B): Boolean = mTOE(a, b)
}
object ops {
implicit class NumberLikeOps[A](a: A) {
def lessThenOrEqual[B](b: B)(implicit numberLike: Aux[A, B]): Boolean =
numberLike.lessThenOrEqual(a, b)
def moreThenOrEqual[B](b: B)(implicit numberLike: Aux[A, B]): Boolean =
numberLike.moreThenOrEqual(a, b)
}
}
implicit val intIntNumberLike: Aux[Int, Int] = instance(_ <= _, _ >= _)
implicit val intFloatNumberLike: Aux[Int, Float] = instance(_ <= _, _ >= _)
implicit val DoubleDoubleNumberLike: Aux[Double, Double] = instance(_ <= _, _ >= _)
implicit val floatFloatNumberLike: Aux[Float, Float] = instance(_ <= _, _ >= _)
}
И теперь я пытаюсь получить экземпляр для побочного продукта
type NumberLikeType = Int :+: Double :+: Float :+: CNil
Я пытаюсь определить, используя бесформенные функцииlessThenOrEqual и moreThenOrEqual, но я не понимаю решение. Вот что я попробовал:
implicit val cnilNumericalLike: NumberLike[CNil] =
new NumberLike[CNil] {
override def lessThenOrEqual(a: CNil, b: B): Boolean = true
override def moreThenOrEqual(a: CNil, b: B): Boolean = true
}
implicit def coproductConsTransform[L, R, LL, RR <: Coproduct](
implicit
lch: NumberLike[L],
lch2: NumberLike[LL],
rch: NumberLike[R],
rch2: NumberLike[RR]): NumberLike[L :+: R] =
new NumberLike[L :+: R] {
override def lessThenOrEqual(t: L :+: R, b: LL :+: RR): Boolean = {
t match {
case Inl(l) =>
b match {
case Inl(ll) => lch.lessThenOrEqual(l, ll)
case Inr(rr) => lch.lessThenOrEqual(l, rr)
}
case Inr(r) => rch.lessThenOrEqual(r, b)
}
}
override def moreThenOrEqual(t: L :+: R, b: L :+: R): Boolean = {
t match {
case Inl(l) =>
b match {
case Inl(bl) => lch.moreThenOrEqual(l, bl)
case Inr(br) => false
}
case Inr(r) =>
b match {
case Inl(bl) => false
case Inr(br) => rch.moreThenOrEqual(r, br)
}
}
}
}
implicit def genericTransform[A, B](implicit
gen: Generic.Aux[A, B],
cch: Lazy[NumberLike[B]]): NumberLike[A] =
new NumberLike[A] {
def lessThenOrEqual(a: A, b: A): Boolean =
cch.value.lessThenOrEqual(gen.to(a), gen.to(b))
def moreThenOrEqual(a: A, b: A): Boolean =
cch.value.moreThenOrEqual(gen.to(a), gen.to(b))
}
Я знаю, что типы ввода неверны, но не знаю, что ввести еще.
EDIT2:
Я пробовал несколько комбинаций, но даже через
NumberLike[NumberLikeType, NumberLikeType]
выдает ошибку: Ошибка: (107,29) расходящееся неявное расширение для типа utils.NumberLike.NumberLike.Aux [Int, Int], начиная с метода genericTransform в объекте NumberLike println (reify (NumberLike [NumberLikeType, NumberLikeType]))
import shapeless.{:+:, CNil, Coproduct, Generic, Inl, Inr, Lazy}
trait NumberLike[A] {
type B
def lessThenOrEqual(a: A, b: B): Boolean
def moreThenOrEqual(a: A, b: B): Boolean
}
object NumberLike {
type Aux[A, B0] = NumberLike[A] { type B = B0 }
def apply[A, B](implicit numberLike: Aux[A, B]): Aux[A, B] =
numberLike
def lessThenOrEqual[A, B](a: A)(b: B)(
implicit numberLike: Aux[A, B]): Boolean =
numberLike.lessThenOrEqual(a, b)
def moreThenOrEqual[A, B](a: A)(b: B)(
implicit numberLike: Aux[A, B]): Boolean =
numberLike.moreThenOrEqual(a, b)
def instance[A, B0](
lTOE: (A, B0) => Boolean,
mTOE: (A, B0) => Boolean
): Aux[A, B0] = new NumberLike[A] {
type B = B0
def lessThenOrEqual(a: A, b: B): Boolean = lTOE(a, b)
def moreThenOrEqual(a: A, b: B): Boolean = mTOE(a, b)
}
object ops {
implicit class NumberLikeOps[A](a: A) {
def lessThenOrEqual[B](b: B)(implicit numberLike: Aux[A, B]): Boolean =
numberLike.lessThenOrEqual(a, b)
def moreThenOrEqual[B](b: B)(implicit numberLike: Aux[A, B]): Boolean =
numberLike.moreThenOrEqual(a, b)
}
}
implicit val intIntNumberLike: Aux[Int, Int] = instance(_ <= _, _ >= _)
implicit val intFloatNumberLike: Aux[Int, Float] = instance(_ <= _, _ >= _)
implicit val intDoubleNumberLike: Aux[Int, Double] = instance(_ <= _, _ >= _)
implicit val DoubleIntNumberLike: Aux[Double, Int] = instance(_ <= _, _ >= _)
implicit val DoubleFloatNumberLike: Aux[Double, Float] = instance(_ <= _, _ >= _)
implicit val DoubleDoubleNumberLike: Aux[Double, Double] = instance(_ <= _, _ >= _)
implicit val floatIntNumberLike: Aux[Float, Int] = instance(_ <= _, _ >= _)
implicit val floatFloatNumberLike: Aux[Float, Float] = instance(_ <= _, _ >= _)
implicit val floatDoubleNumberLike: Aux[Float, Double] = instance(_ <= _, _ >= _)
implicit val cnilNumericalLike: Aux[CNil, CNil] = instance((_, _) => true, (_, _) => true)
implicit val intCnilNumericalLike: Aux[Int, CNil] = instance((_, _) => true, (_, _) => true)
implicit val floatCnilNumericalLike: Aux[Float, CNil] = instance((_, _) => true, (_, _) => true)
implicit val doubleCnilNumericalLike: Aux[Double, CNil] = instance((_, _) => true, (_, _) => true)
implicit val cnilIntNumericalLike: Aux[CNil, Int] = instance((_, _) => true, (_, _) => true)
implicit val cnilFloatNumericalLike: Aux[CNil, Float] = instance((_, _) => true, (_, _) => true)
implicit val cnilDoubleNumericalLike: Aux[CNil, Double] = instance((_, _) => true, (_, _) => true)
implicit def coproductConsTransform[L, R <: Coproduct, LL, RR <: Coproduct](
implicit
lch: Aux[L, LL],
lch1: Aux[L, RR],
rch: Aux[R, LL :+: RR],
lch2: Aux[L, LL :+: RR],
rch1: Aux[R, RR],
rch2: Aux[R, LL],
ua: Aux[L :+: R, LL],
ua2: Aux[L :+: R, RR]): Aux[L :+: R, LL :+: RR] =
instance(
{
case (Inl(l), Inl(ll)) => lch.lessThenOrEqual(l, ll)
case (Inl(l), Inr(rr)) => lch1.lessThenOrEqual(l, rr)
case (Inr(r), Inl(ll)) => rch2.lessThenOrEqual(r, ll)
case (Inr(r), Inr(rr)) => rch1.lessThenOrEqual(r, rr)
}, {
case (Inl(l), Inl(ll)) => lch.moreThenOrEqual(l, ll)
case (Inl(l), Inr(rr)) => lch1.moreThenOrEqual(l, rr)
case (Inr(r), Inl(ll)) => rch2.moreThenOrEqual(r, ll)
case (Inr(r), Inr(rr)) => rch1.moreThenOrEqual(r, rr)
}
)
implicit def coproductConsTransform2[L,R <: Coproduct, CNil]
(
implicit
lch: Aux[L, CNil],
rch: Aux[R, CNil]
): Aux[L :+: R, CNil] =
instance(
{
case (Inl(l), _) => true
case (Inr(r), _) => true
}, {
case (Inl(l), _) => true
case (Inr(r), _) => true
}
)
implicit def coproductConsTransform3[L,R <: Coproduct, CNil]
(
implicit
lch: Aux[L, CNil],
rch: Aux[R, CNil]
): Aux[CNil, L :+: R] =
instance(
{
case ( _, Inl(l)) => true
case ( _, Inr(r)) => true
}, {
case ( _, Inl(l)) => true
case ( _, Inr(r)) => true
}
)
implicit def genericTransform[A, B, ARepr, BRepr](
implicit
gen: Generic.Aux[A, ARepr],
gen1: Generic.Aux[B, BRepr],
cch: Lazy[Aux[ARepr, BRepr]]): Aux[A, B] =
instance(
(a, b) => cch.value.lessThenOrEqual(gen.to(a), gen1.to(b)),
(a, b) => cch.value.moreThenOrEqual(gen.to(a), gen1.to(b))
)
}