抱歉,我很难找到问题的相关标题。
我想建模以下行为:我设计了一个带有表达式的“语言”,这些表达式封装了标准的Scala类型。表达式可以是变量或表达式序列。在下文中,A可以是标准Scala类型(即Boolean,Int,Double)。我还想实现一种方法来替换表达式中的其他表达式(特别是在序列中)。我尝试了一些我无法编译的代码。当我不知道要放什么类型的时候我放了引号,但所有这些都可能是凌乱的。由于它的递归性质,我对序列事物有特殊的麻烦。
sealed trait Expression[A] {
def replace[B](a: Expression[B], b: Expression[B]): Expression[?]
}
trait Variable[A] extends Expression[A] {
def replace[B](a: Expression[B], b: Expression[B]) =
if (a == this) b else this
}
case class Sequence[A <: Expression[B]](values: Seq[A]) extends Expression[A] {
def replace[B](a: Expression[B], b: Expression[B]) =
if (a == this) b
else Sequence(values.map(_.replace(a, b)))
}
我当然假设序列是非循环的(序列不能包含自身),因为它会触发无限递归。这些用于实现n-ary矩阵。
感谢您的帮助。
答案 0 :(得分:3)
看起来你遇到了一个Scala没有优雅解决方案的角落案例。
您需要代替Expression[?]
作为返回类型实际上是一种表示“此类型”的类型,它是特征实际混合的类型。 Scala中没有简写方法可以让您以简单的方式表达这一点,并且您也不能使用this.type
,因为它太具体,只能在您真正总是返回this
时使用。
解决方案通常会快速引入令人费解的样板。例如,Scala集合遇到了同样的问题,像MapLike
这样的特征需要编码类似的东西。
我尝试快速修改您的样本以对此类型进行编码。我确定它编译,但我没有运行它:
sealed trait Expression[A, ThisType <: Expression[A, ThisType]] {
def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]): ThisType
}
trait Variable[A] extends Expression[A, Variable[A]] {
def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]) =
if (a == this) b.asInstanceOf[Variable[A]] else this
}
case class Sequence[A <: Expression[_,A]](values: Seq[A]) extends Expression[A, Sequence[A]] {
def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]) =
if (a == this) b.asInstanceOf[Sequence[A]]
else Sequence(values.map(_.replace(a, b)))
}
它甚至必须使用一个演员,这通常是一种气味,但我不确定在这种情况下是否有办法避免它。至少它是安全的,我们知道它必须具有正确的类型,只是编译器不知道它。 : - )
答案 1 :(得分:1)
通常在这种情况下,A
和B
之间存在必需的关系。例如,考虑将元素添加到(假设的和高度简化的)序列类型时会发生什么:
class Sequence[+A] {
def +: [B >: A](b: B): Sequence[B] = {
/* Build the new sequence with b at the beginning and this sequence's elments after */
}
}
因此,在您的情况下(如果此模式适用于您),Expression[A]
中的签名将为:
def replace[B >: A](a: Expression[B], b: Expression[B]): Expression[B]
答案 2 :(得分:0)
感谢您的回答。我结束了简化问题以获得更简单的解决方案。我简单地“扁平化”了序列的类型参数:
case class Sequence[A] (values: Seq[Expression[A]]) extends Expression[A] {
def replace[B <: A](a: Expression[A], b: Expression[B]) {
// (Code in initial question)
}
}
A
中的 Expression
现在意味着Expression
是A
类型的变量,类型为A
的变量序列,序列序列A
...
我在这里失去了表现力,但获得了可用性。 Expression的两个参数变得过于复杂,破坏了Java的互操作性。也许我会稍后尝试改进这个。