1

抱歉,我很难为我的问题找出一个相关的标题。

我想对以下行为进行建模:我设计了一种“语言”,其中包含封装标准 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 元矩阵。

谢谢你的帮助。

4

3 回答 3

3

看起来您遇到了 Scala 没有优雅解决方案的极端情况之一。

您需要代替Expression[?]返回类型的实际上是表示“这种类型”的类型,即特征实际混合到的类型。Scala 中没有简写可以让您以简单的方式表达这一点,您也不能使用this.type任何一种,因为这太具体了,只能在您真的总是 return 时使用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)))
}

它甚至必须使用演员表,这通常是一种气味,但我不确定在这种情况下是否有办法避免它。至少它是安全的,我们知道它必须有正确的类型,只是编译器不知道。:-)

于 2014-02-19T23:11:11.507 回答
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]
于 2014-02-19T16:32:34.913 回答
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)
  }
}

Ain Expressionnow 意味着它Expression要么是一个类型A的变量,一个类型的变量序列A,一个类型的变量序列序列A......</p>

我在这里失去了表现力,但获得了可用性。Expression 有两个参数变得太复杂了,并且破坏了 Java 的互操作性。也许我会在以后尝试改进这一点。

于 2014-02-21T13:37:36.290 回答