Тип класса NumberLike экземпляр для Coproduct с бесформенным - PullRequest
0 голосов
/ 30 сентября 2019

Я хочу представить класс типов с номерами сравнения, такими как типы, но также и даты.

Вот мой класс типов:

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))
    )
}

1 Ответ

2 голосов
/ 30 сентября 2019

Похоже, у вас есть класс с несколькими параметрами.

trait NumberLike[A, B] {
  def lessThenOrEqual(a: A, b: B): Boolean
  def moreThenOrEqual(a: A, b: B): Boolean
}

object NumberLike {
  def apply[A, B](implicit numberLike: NumberLike[A, B]): NumberLike[A, B] =
    numberLike

  def lessThenOrEqual[A, B](a: A)(b: B)(implicit numberLike: NumberLike[A, B]): Boolean =
    numberLike.lessThenOrEqual(a, b)
  def moreThenOrEqual[A, B](a: A)(b: B)(implicit numberLike: NumberLike[A, B]): Boolean =
    numberLike.moreThenOrEqual(a, b)

  def instance[A, B](
                      lTOE: (A, B) => Boolean,
                      mTOE: (A, B) => Boolean
                    ): NumberLike[A, B] = new NumberLike[A, B] {
    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, B](a: A) {
      def lessThenOrEqual(b: B)(implicit numberLike: NumberLike[A, B]): Boolean = numberLike.lessThenOrEqual(a, b)
      def moreThenOrEqual(b: B)(implicit numberLike: NumberLike[A, B]): Boolean = numberLike.moreThenOrEqual(a, b)
    }
  }

  implicit val intIntNumberLike: NumberLike[Int, Int] = instance(_ <= _, _ >= _)
  implicit val intFloatNumberLike: NumberLike[Int, Float] = instance(_ <= _, _ >= _)
}

import NumberLike.ops._
1 lessThenOrEqual 2
1 lessThenOrEqual 2.0f

Также вы можете перемещать B для ввода членов, как рекомендовано @ LuisMiguelMejíaSuárez

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(_ <= _, _ >= _)
}

import NumberLike.ops._
1 lessThenOrEqual 2
1 lessThenOrEqual 2.0f

Если вы сохраняете B на уровне метода, вы не можете использовать метод конструктора instance (в Scala 2 нет полиморфных функций, они появятся только в Scala 3). Вы должны создавать экземпляры через new. Также неясно, как вы собираетесь определять экземпляры, например, как сравнить Int с произвольным B.

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 numberLike: NumberLike[A]): NumberLike[A] =
    numberLike

  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)

  object ops {
    implicit class NumberLikeOps[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)
    }
  }

  implicit val intNumberLike: NumberLike[Int] = new NumberLike[Int] {
    override def lessThenOrEqual[B](a: Int, b: B): Boolean = ???
    override def moreThenOrEqual[B](a: Int, b: B): Boolean = ???
  }
}

Попробуйте

implicit val cnilNumericalLike: Aux[CNil, CNil] = 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],
                                                                            rch1: Aux[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), b)       => rch.lessThenOrEqual(r, b)
  }, {
    case (Inl(l), Inl(bl)) => lch.moreThenOrEqual(l, bl)
    case (Inl(l), Inr(br)) => false
    case (Inr(r), Inl(bl)) => false
    case (Inr(r), Inr(br)) => rch1.moreThenOrEqual(r, br)
  })

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))
  )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...