【问题标题】:Scala Type classes and don't work well with inheritenceScala 类型类和继承不能很好地工作
【发布时间】:2016-05-20 03:41:08
【问题描述】:

我目前编写了一些实现类型类的类。我为此目的使用猫。在此设置中,我有课程 A[T]B[T] <: A[T]A[T] 是一个 monad,所以在导入正确的库时,我可以写

val x: A[Int] = ???
x.flatMap(_)

但我不会写

val x: B[Int] = ???
b.flatMap(_)

因为 scala 没有找到 flatMap 运算符。 相反,我必须写

val x: B[Int] = ???
(b: A[Int]).flatMap(_)

为此工作。这很尴尬,因为我希望子类继承超类的方法。

为了完整起见,我添加了一个没有依赖关系的最小示例来显示问题。其中Filterable 是一个类型类,由S 实现。

object StackOverflowTest {
  class S[+T]

  class Q[+T] extends S[T]

  trait Filterable[F[+_]] {
    def filter[A](x: F[A]): F[A]
  }

  implicit class FilterOps[F[+_], A](y: F[A])(implicit ev: Filterable[F]) {
    def filter: F[A] = ev.filter(y)
  }

  implicit object SIsFilterable extends Filterable[S] {
    def filter[A](x: S[A]): S[A] = x
  }

  //def failing = {
  //  val q = new Q[Int]()
  //  val r = q.filter
  //}

  def working = {
    val q = new Q[Int]()
    val r = (q: S[Int]).filter
  }
}

failing 定义无法编译,因为未找到 q.op。另一方面,working 通过首先转换为 S 来缓解此问题。我该怎么做才能使failing 示例适用于我图书馆的用户?您必须强制转换为父类型才能使用它的方法,这感觉非常不自然。

请注意,我无法定义第二个实现 Filterable[Q] 的隐式对象,因为 (new Q[Int]()).filter 的类型应该是 S[Int] 而不是 Q[Int]

【问题讨论】:

  • 类似的问题是Some vs Option。这就是为什么猫为XorValidated、...提供智能构造函数的原因,因此您不会以Validated.Valid[Int] 结尾,而是以Validated[Nothing, Int] 结尾。也许可以使用Q 遵循类似的策略?
  • @PeterNeyens:不幸的是,这种策略是不可能的,因为 Q 有一些我想向用户公开的附加功能

标签: scala scala-cats


【解决方案1】:

尝试将SIsFilterable 替换为:

implicit def sOrSubtypeIsFilterable [T[+_] <: S[_]] = new Filterable[T] {
  def filter[A](x: T[A]): T[A] = x
}

【讨论】:

  • filter的返回类型应该是S[A],那么这似乎确实解决了问题。我想知道这是否也适用于猫;添加第二个隐式时,我可能会遇到含糊不清的隐式定义的问题。
  • 为什么要返回S[A]?您不想过滤后的Q[...] 仍然是Q[...]吗?
  • 在我的用例中filter有点复杂,只能返回一个S[A]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多