当前位置: 首页 > 知识库问答 >
问题:

继承和自递归类型推理

毕和志
2023-03-14

(Scala 2.11.8)

我有一个类似GenTableLike的特征,具有复杂的自递归类型签名,它定义了连接兼容表实现的方法。我还有一个层次结构

下面是一个稍微简化的片段,其中问题仍然存在:

trait GenTableLike[RKT,
                   CKT,
                   +A,
                   +SelfType[+A2] <: GenTableLike[RKT, CKT, A2, SelfType, TransposedType],
                   +TransposedType[+A2] <: GenTableLike[CKT, RKT, A2, TransposedType, SelfType]] {
  def ++[B >: A,
         T2 <: GenTableLike[RKT, CKT, B, ST, TT],
         ST[+A2] <: GenTableLike[RKT, CKT, A2, ST, TT],
         TT[+A2] <: GenTableLike[CKT, RKT, A2, TT, ST]](that: T2): SelfType[B] = ???
}

trait KeyTable[RKT, CKT, +A]
  extends GenTableLike[RKT,
                       CKT,
                       A,
                       KeyTable.Curried[RKT, CKT]#Self,
                       KeyTable.Curried[CKT, RKT]#Self]

object KeyTable {
  /** Type helper for defining self-recursive type */
  type Curried[RKT, CKT] = {
    type Self[+A] = KeyTable[RKT, CKT, A]
  }
}

class MapKeyTable[RKT, CKT, +A]
  extends KeyTable[RKT, CKT, A]
  with GenTableLike[RKT,
                    CKT,
                    A,
                    MapKeyTable.Curried[RKT, CKT]#Self,
                    MapKeyTable.Curried[CKT, RKT]#Self]

object MapKeyTable {
  /** Type helper for defining self-recursive type */
  type Curried[RKT, CKT] = {
    type Self[+A] = MapKeyTable[RKT, CKT, A]
  }
}

val t1: MapKeyTable[Int, String, Int] = ???
val t2: MapKeyTable[Int, String, Any] = ???

// The following works
t1.++[Any, MapKeyTable[Int, String, Any], ({ type ST[+A2] = MapKeyTable[Int, String, A2] })#ST, ({ type TT[+A2] = MapKeyTable[String, Int, A2] })#TT](t2)
t1.++[Any, MapKeyTable[Int, String, Any], MapKeyTable.Curried[Int, String]#Self, MapKeyTable.Curried[String, Int]#Self](t2)
// Error: inferred type arguments [Int,MapKeyTable[Int,String,Any],Nothing,Nothing] do not conform to method ++'s type parameter bounds [B >: Int,T2 <: GenTableLike[Int,String,B,ST,TT],ST[+A2] <: GenTableLike[Int,String,A2,ST,TT],TT[+A2] <: GenTableLike[String,Int,A2,TT,ST]]
t1 ++ t2

我是不是做错了什么?

自类型和转置类型用于定义函数返回类型。我还有一个IndexedTable实现定义如下,所以我不能返工自类型以接受3个参数

trait IndexedTable[+A]
    extends GenTableLike[Int,
                         Int,
                         A,
                         IndexedTable,
                         IndexedTable]

class IndexedSeqTable[+A]
    extends IndexedTable[A]
    with GenTableLike[Int,
                      Int,
                      A,
                      IndexedSeqTable,
                      IndexedSeqTable]

共有2个答案

罗均
2023-03-14

我设法找到了我的问题的解决方案,我认为它比@PH88的提议更好。我删除了SelfType/TransposedType中的约束,并在参数类型中使用了ST for某些{type ST[A2]}语法,如https://issues.scala-lang.org/browse/SI-8039

此解决方案的副作用:

  1. 无法根据其他方法定义GenTablelike中的方法实现(因为它们将返回未知性质的SelfType-即无法重用GenTablelike代码中的方法。这可以通过在GenTablelike下面和KeyTableIndexedTable
  2. 上面提供额外的继承层来解决。
  3. 子类可以将非表定义为它们的自/转置类型,但这似乎不是一个大问题——它们没有理由这样做。

结果代码:

trait GenTableLike[RKT,
                   CKT,
                   +A,
                   +SelfType[+A2],
                   +TransposedType[+A2]] {
  def ++[B >: A](that: GenTableLike[RKT,
                                    CKT,
                                    B,
                                    ST forSome { type ST[+A2] },
                                    TT forSome { type TT[+A2] }]): SelfType[B] = ???
}

// Common ancestor for all table classes
trait GenTable[RKT, CKT, +A]
  extends GenTableLike[RKT,
                       CKT,
                       A,
                       GenTable.Curried[RKT, CKT]#Self,
                       GenTable.Curried[CKT, RKT]#Self] {
  // Here we can implement common methods reusing other methods due to proper SelfType bounds
}

object GenTable {
  /** Type helper for defining self-recursive type */
  private type Curried[RKT, CKT] = {
    type Self[+A] = GenTable[RKT, CKT, A]
  }
}

trait KeyTable[RKT, CKT, +A]
  extends GenTable[RKT, CKT, A]
  with GenTableLike[RKT,
                    CKT,
                    A,
                    KeyTable.Curried[RKT, CKT]#Self,
                    KeyTable.Curried[CKT, RKT]#Self]

object KeyTable {
  /** Type helper for defining self-recursive type */
  type Curried[RKT, CKT] = {
    type Self[+A] = KeyTable[RKT, CKT, A]
  }
}

class MapKeyTable[RKT, CKT, +A]
  extends KeyTable[RKT, CKT, A]
  with GenTableLike[RKT,
                    CKT,
                    A,
                    MapKeyTable.Curried[RKT, CKT]#Self,
                    MapKeyTable.Curried[CKT, RKT]#Self] {
  override def ++[B >: A](that: GenTableLike[RKT,
                                             CKT,
                                             B,
                                             ST forSome { type ST[+A2] },
                                             TT forSome { type TT[+A2] }]): MapKeyTable[RKT, CKT, B] = {
    new MapKeyTable
  }
}

object MapKeyTable {
  /** Type helper for defining self-recursive type */
  type Curried[RKT, CKT] = {
    type Self[+A] = MapKeyTable[RKT, CKT, A]
  }
}

trait IndexedTable[+A]
  extends GenTable[Int, Int, A]
  with GenTableLike[Int,
                    Int,
                    A,
                    IndexedTable,
                    IndexedTable]

class IndexedSeqTable[+A]
    extends IndexedTable[A]
    with GenTableLike[Int,
                      Int,
                      A,
                      IndexedSeqTable,
                      IndexedSeqTable] {
  override def ++[B >: A](that: GenTableLike[Int,
                                             Int,
                                             B,
                                             ST forSome { type ST[+A2] },
                                             TT forSome { type TT[+A2] }]): IndexedSeqTable[B] = {
    new IndexedSeqTable
  }
}


// Usage

def s1: IndexedSeqTable[Int] = ???
def s2: IndexedSeqTable[Any] = ???

def t1: MapKeyTable[Int, Int, Int] = ???
def t2: MapKeyTable[Int, Int, Any] = ???

// All of this works with result being of proper type
t1.++[Any](t2)
t1 ++ t2
s1 ++ s2
t1 ++ s1
s1 ++ t1
s2 ++ t1
韩安顺
2023-03-14

把SelfType和TransposeType转换成抽象类型怎么样?这更简单,也更有效:

import scala.language.higherKinds

trait GenTableLike[RKT, CKT, +A] {
  type SelfType[+A2] <: GenTableLike[RKT, CKT, A2]
  type TransposedType[+A2] <: GenTableLike[CKT, RKT, A2]

  def ++[B >: A](that: GenTableLike[RKT, CKT, B]): SelfType[B]
}

trait KeyTable[RKT, CKT, +A]
  extends GenTableLike[RKT, CKT, A] {
  override type SelfType[+A2] <: KeyTable[RKT, CKT, A2]
  override type TransposedType[+A2] <: KeyTable[CKT, RKT, A2]
}

class MapKeyTable[RKT, CKT, +A]
  extends KeyTable[RKT, CKT, A] {
  override type SelfType[+A2] = MapKeyTable[RKT, CKT, A2]
  override type TransposedType[+A2] = MapKeyTable[CKT, RKT, A2]

  override def ++[B >: A](that: GenTableLike[RKT, CKT, B]): MapKeyTable[RKT, CKT, B] =
    new MapKeyTable[RKT, CKT, B]
}

val t1 = new MapKeyTable[Int, String, Int]
val t2 = new MapKeyTable[Int, String, Any]

// The following works
t1.++[Any](t2)
t1 ++ t2


trait IndexedTable[+A]
  extends GenTableLike[Int, Int, A] {
  override type SelfType[+A2] <: IndexedTable[A2]
  override type TransposedType[+A2] <: IndexedTable[A2]
}

class IndexedSeqTable[+A]
  extends IndexedTable[A] {
  override type SelfType[+A2] = IndexedSeqTable[A2]
  override type TransposedType[+A2] = IndexedSeqTable[A2]

  override def ++[B >: A](that: GenTableLike[Int, Int, B]): IndexedSeqTable[B] = new IndexedSeqTable[B]
}

2月15日针对Alex的评论进行了更新:

递归类型继承很复杂,如果可能的话,我总是避免它:-)
如果SelfType和TransposeType仅用作函数返回类型,如何将SelfType和TransposeType一起删除,并使用隐式生成器,如:

import scala.language.higherKinds

trait GenTableLike[RKT, CKT, +A] {

  def value: A

  def ++[B >: A](that: GenTableLike[RKT, CKT, B])(implicit builder: GenTableLike.Builder[this.type, B]): builder.Self = {
    builder.buildSelf(that.value)
  }

  def transpose(implicit builder: GenTableLike.Builder[this.type, A]) = builder.buildTranspose(value)

}

object GenTableLike {

  trait Builder[-This, -A] {
    type Self
    type Transpose

    def buildSelf(a: A): Self

    def buildTranspose(a: A): Transpose
  }

}

trait KeyTable[RKT, CKT, +A]
  extends GenTableLike[RKT, CKT, A] {
}

class MapKeyTable[RKT, CKT, +A](override val value: A)
  extends KeyTable[RKT, CKT, A] {
}

object MapKeyTable {

  implicit def builder[RKT, CKT, A] = new GenTableLike.Builder[MapKeyTable[RKT, CKT, A], A] {
    override type Self = MapKeyTable[RKT, CKT, A]
    override type Transpose = MapKeyTable[CKT, RKT, A]

    override def buildSelf(a: A): Self = new MapKeyTable[RKT, CKT, A](a)

    override def buildTranspose(a: A): Transpose = new MapKeyTable[CKT, RKT, A](a)
  }

}

class MapKeyTableEx[RKT, CKT, +A](override val value: A)
  extends MapKeyTable[RKT, CKT, A](value)

object MapKeyTableEx {
  implicit def builder[RKT, CKT, A] = new GenTableLike.Builder[MapKeyTableEx[RKT, CKT, A], A] {
    override type Self = MapKeyTableEx[RKT, CKT, A]
    override type Transpose = MapKeyTableEx[CKT, RKT, A]

    override def buildSelf(a: A): Self = new MapKeyTableEx[RKT, CKT, A](a)

    override def buildTranspose(a: A): Transpose = new MapKeyTableEx[CKT, RKT, A](a)
  }

}


val t1 = new MapKeyTable[Int, String, Int](1)
val t2 = new MapKeyTable[Int, String, Any]("b")
val t3 = new MapKeyTableEx[Int, String, Int](1)
val t4 = new MapKeyTableEx[Int, String, Any]("b")

// The following works
t1 ++ t2
t1 ++ t3
t2 ++ t3
t3 ++ t4

t1.transpose
t2.transpose
t3.transpose
t4.transpose
 类似资料:
  • 查看我在某处(这里是游乐场)找到的这个Typescript4.2片段: 我的头不能绕着它。TS如何处理这件事?它怎么不卡在无限递归里?具体地说,对于和的情况,悬停在变量上显示TS将类型解析为和。这是怎么回事?

  • 我在Hibernate中有道传承,下面是代码: 用户DAO: 我有一个域类用户和两个子类用户:Customer和Sales。我有两个dao类,分别用于客户和销售。 用户DAO: 客户道: 销售DAO: 我的问题是,当我使用CusterDap调用方法getUserByUsername()(继承自BaseDaoImpl)与销售的用户名(拥有用户名的用户是SalesRep的实例,而不是客户)时,它会抛出

  • 我正在自己学习swift,但我无法让这个代码运行,我正在尝试创建一个类“Inhabitant”,它继承了Person类的一个新的“Country”属性,有两个初始值设定项:-一个接受firstname和lastname,并将Country设置为空String-一个接收firstname,lastname和country,并创建String类型的计算属性描述,该描述返回由空格分隔的名字、姓氏和国家

  • 在面向对象的程序设计中,定义一个新的 class 的时候,可以从某个现有的 class 继承,新的 class 称为子类,而被继承的 class 称为基类、父类或超类。 Python 中继承的语法如下: class Parent: pass class Child(Parent): pass 在第 1 行,定义了父类 Parent; 在第 4 行,定义了子类 Child,语法

  • 标准 ML 没有多态递归。在模块语言中添加递归允许我们使用内函子的固定点将多态递归恢复为一种特殊情况。例如: 众所周知,多态递归使得类型推理不可判定。然而,函子定义已经包含部分类型信息,即其参数的签名。这些信息足以使类型推理再次可判定吗?

  • 默认任何类都是基础继承自Any(与java中的Object类似),但是我们可以继承其它类。所有的类默认都是不可继承的(final),所以我们只能继承那些明确声明open或者abstract的类: open class Animal(name: String) class Person(name: String, surname: String) : Animal(name) 当我们只有单个构造器时