type class NumberLike实例不带形状

问题描述 投票:0回答:1

我想引入一个具有比较编号的类型类,例如类型,但还要有日期。

这是我的类型类别:

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

现在我正在尝试获取Hlist的实例

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

我知道输入类型是错误的,但是不知道要介绍什么。

scala types functional-programming typeclass
1个回答
1
投票

听起来像您具有多参数类型类。

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

也可以按照@LuisMiguelMejíaSuárez的建议移动B来键入成员

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中只有will appear)。您应该通过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 = ???
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.