scala - 如何在 Scala 中参数化具有继承类型的函数

标签 scala compilation

假设我已经定义了这些类(这是我的代码的简化版本)

sealed trait Expression

trait ExpressionA extends Expression
trait ExpressionB extends Expression

case class OperationA(op: String, a: ExpressionA, b:ExpressionA) extends ExpressionA
case class OperationB(op: String, a: ExpressionB, b:ExpressionB) extends ExpressionB
case class ComparisonB(op: String, a: ExpressionA, b:ExpressionA) extends ExpressionB
case class VariableA(op: String, a: ExpressionA) extends ExpressionA

然后我想替换 VariableA 类中的给定字符串 这样我就可以写

def replace(exp: ExpressionB, operation: String => String): ExpressionB = exp match {
  case ComparisonB(op, a, b) => ComparisonB(op, replace(a, operation), replace(b, operation))
  case OperationB(op, a, b) => OperationB(op, replace(a, operation), replace(b, operation))

}

def replace(exp: ExpressionA, operation: String => String): ExpressionA = exp match {
  case OperationA(op, a, b) => OperationA(op, replace(a, operation), replace(b, operation))
  case VariableA(name) => VariableA(operation(name))
}

但我想将这两个函数合并为一个,并具有通用类型。

这是我尝试过的

def replace[T <: Expression](exp:T, operation: String => String):T = exp match {
  case ComparisonB(op, a, b) => ComparisonB(op, replace(a, operation), replace(b, operation))
  case OperationB(op, a, b) => OperationB(op, replace(a, operation), replace(b, operation))
  case OperationA(op, a, b) => OperationA(op, replace(a, operation), replace(b, operation))
  case VariableA(name) => VariableA(operation(name))
}

我收到错误

Expression of type ExpressionA does not conform to expected type T

尽管理论上它始终与输入具有相同的类型。所以我不知道我的代码有什么问题,是否缺少一些隐式内容,或者执行方法错误?

最佳答案

如果您希望 replace 的返回类型取决于 exp 的值(即 exp 是否匹配特定模式),那么实际上您想要一个polymorphic功能。

  trait Replacer[T <: Expression] {
    def replace(exp: T, operation: String => String): T
  }

  object Replacer {
    implicit val exprA: Replacer[ExpressionA] =
      (exp: ExpressionA, operation: String => String) => exp match {
        case OperationA(op, a, b) => OperationA(op, replace(a, operation), replace(b, operation))
        case VariableA(name) => VariableA(operation(name))
      }

    implicit val exprB: Replacer[ExpressionB] =
      (exp: ExpressionB, operation: String => String) => exp match {
        case ComparisonB(op, a, b) => ComparisonB(op, replace(a, operation), replace(b, operation))
        case OperationB(op, a, b) => OperationB(op, replace(a, operation), replace(b, operation))
      }
  }

  def replace[T <: Expression](exp: T, operation: String => String)(implicit replacer: Replacer[T]): T =
    replacer.replace(exp, operation)

关于scala - 如何在 Scala 中参数化具有继承类型的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48475187/

相关文章:

mysql - Play 2.4 - Slick 3.0.0 - DELETE 不起作用

scala - Spark - 按输出 (RDD) 从组中删除 CompactBuffer

ios在不支持ac3的情况下编译ffmpeg

c - 用于编译和运行 .c 文件的 Visual Studio Code 任务

c++ - 在 netbeans 7.1.1 中 boost 库

c++ - Opencv 函数只能以 C 代码方式调用,不能以 C++ 方式调用

scala - 在scala中警告或避免整数除法(导致截断)

scala - 如何遍历在单个 scala.xml.Node 中找到的子项列表

scala - 为什么添加 import `import cats.instances.future._` 会导致隐式 Functor[Future] 编译错误

scala - 使用Actor池有意义吗?