【问题标题】:Define a common trait for types with different numbers of type parameters为具有不同类型参数数量的类型定义一个共同特征
【发布时间】:2015-11-22 16:53:18
【问题描述】:

假设我有两个特征:

trait Generic1[T] {
  def mapR[U](f: Result[T] => Result[U]): Generic1[U]
}

trait Generic2[A, T] {
  // pretty much the same as Generic1, but with the extra `A` type param
  def mapR[U](f: Result[T] => Result[U]): Generic2[A, U]
}

有没有一种方法可以定义一个单一的特征来定义基于mapR 方法的一些常见功能?

// for example
trait MapR[T, ???] {
  def mapR[U](f: Result[T] => Result[U]): ???[U]

  def map[U](f: T => U): ???[U] = mapR(_ map f)
  def flatMap[U](f: T => Result[U]): ???[U] = mapR(_ flatMap f)
  def withFilter(f: T => Boolean): ???[T] = mapR(_ withFilter f)
}

如何在上面的 MapR 特征中定义 ??? 以便我可以定义

trait Generic1[T] extends MapR[T, ???]
trait Generic2[A, T] extends MapR[T, ???]

额外问题

@m-z 的回答处理了上面提出的问题,但是当 GenericN 特征具有类型差异时,我遇到了一些进一步的麻烦:

trait Generic1[+T] extends MapR[T] {
  type R[X] = Generic1[X]
  ...
}
trait Generic2[-A, +T] extends MapR[T] {
  type R[X] = Generic2[A, X]
  ...
}

我收到类似“逆变类型 A 出现在类型 R 的类型 [X]Generic2[A, X] 的不变位置”之类的错误

我尝试将 R 重新定义为协变,但它仍然没有触及 A 类型,并且我得到了类似的错误。

可以调整答案中的方法来处理上述类型差异吗?

【问题讨论】:

    标签: scala generics


    【解决方案1】:

    你可以让MapR trait 有一个类型成员和一个类型参数,而不是在实现时给Generic trait 加上别名。这将要求每个 Generic 特征描述它是如何参数化的。

    trait Result[T]
    
    trait MapR[T] {
    
      type R[U]
    
      def mapR[U](f: Result[T] => Result[U]): R[U]
    
    }
    
    trait Generic1[T] extends MapR[T] {
      type R[U] = Generic1[U]
    }
    
    trait Generic2[A, T] extends MapR[T] {
      type R[U] = Generic2[A, U]
    }
    

    【讨论】:

    • 我接受,因为这回答了我提出的问题。但我忽略了(为简洁起见)我的实际 GenericN 特征在 T 上是协变的,在 A 上是逆变的这一事实。按照这种方法,我无法让它根据我的实际特征进行编译。我在“额外问题”部分编辑了问题以添加更多信息。
    • @Dylan 你可以使ResultMapRGeneric1Generic2type RT上都是协变的。
    • 这在Generic1 中有效,但在Generic2 中,当我写type R[+U] = Generic2[A, U] 时,我仍然得到“类型中不变位置的逆变类型A...”
    【解决方案2】:

    您可能可以通过将超级特质声明为更高种类来实现这一点。类似的事情可能是可能的:

    trait Result[T]
    
    trait MapRSupport[SelfType[X], T] {
      def mapR[U](f: Result[T] => Result[U]): SelfType[U]
    }
    
    trait Generic1[T] extends MapRSupport[Generic1, T]{
      def mapR[U](f: Result[T] => Result[U]): Generic1[U] = ???
    }
    
    trait Generic2[A] extends MapRSupport[Generic2, A]{
      type T
      // pretty much the same as Generic1, but with the extra `A` type param
      def mapR[U](f: Result[T] => Result[U]): Generic2[A] { type T = U} = ???
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      相关资源
      最近更新 更多