首页 文章

Scala自定义不适用于泛型

提问于
浏览
3

我想通过一个自定义的通用unapply函数来压缩我的求值程序,该函数计算参数并在成功时返回值 .

但这失败了,错误是 error: not found: type Eval

有没有实现这个目标?我看过typetagsimplicit conversions for unapply methods但是我看不出如何将它们整合到这个问题中 . 如何正确定义Eval?

object Test {
  case class Context()

  trait Expr
  trait Literal[T] extends Expr{
    def value : T
  }
  case class IntLiteral(value: Int) extends Literal[Int]
  case class StringLiteral(value: Int) extends Literal[Int]
  case class Plus(e: Expr, f: Expr) extends Expr

  object Eval { // Here I want the magic unapply to evaluate the expression.
    def unapply[T](e: Expr)(implicit gctx: Context): Option[T] = {
      eval(e) match {
        case e: Literal[T] => Some(e.value)
        case _ => None
      }
    }
  }

  def eval(e: Expr)(implicit c: Context): Expr = e match {
    case Plus(Eval[Int](i), Eval[Int](j)) => IntLiteral(i+j) // Fails here.
    case IntLiteral(i) => e
    case StringLiteral(s) => e
  }

  eval(Plus(Plus(IntLiteral(1),IntLiteral(2)),IntLiteral(3)))(Context())
}

1 回答

  • 1

    Eval[Int](...) 根本不是合法模式,因此您无法获得此语法 . 您可以使 Eval 本身通用并为您想要的类型创建实例:

    object Test {
      case class Context()
    
      trait Expr
      trait Literal[T] extends Expr {
        def value: T
      }
      case class IntLiteral(value: Int) extends Literal[Int]
      case class StringLiteral(value: Int) extends Literal[Int]
      case class Plus(e: Expr, f: Expr) extends Expr
    
      case class Eval[T]() {
    
        def unapply(e: Expr)(implicit gctx: Context): Option[T] = {
          eval(e) match {
            case e: Literal[T] => Some(e.value)
            case _             => None
          }
        }
      }
    
      val IntEval = Eval[Int]()
    
      def eval(e: Expr)(implicit c: Context): Expr = e match {
        case Plus(IntEval(i), IntEval(j)) => IntLiteral(i + j) 
    
        case IntLiteral(i)                => e
        case StringLiteral(s)             => e
      }
    
      println(eval(Plus(Plus(IntLiteral(1), IntLiteral(2)), IntLiteral(3)))(Context()))
    }
    

    但请注意,这不会检查文字的类型!如果你也想要这个,你需要 ClassTag ,这只允许匹配 : T ,而不是 : Literal[T]

    object Test {
      case class Context()
    
      trait Expr
      case class Literal[T](value: T) extends Expr // or case class Literal(value: Any)
      case class Plus(e: Expr, f: Expr) extends Expr
    
      case class Eval[T]()(implicit tag: scala.reflect.ClassTag[T]) {
    
        def unapply(e: Expr)(implicit gctx: Context): Option[T] = {
          eval(e) match {
            case Literal(value: T) => Some(value)
            case _             => None
          }
        }
      }
    
      val IntEval = Eval[Int]()
    
      def eval(e: Expr)(implicit c: Context): Expr = e match {
        case Plus(IntEval(i), IntEval(j)) => Literal(i + j)
    
        case e: Literal[_]                => e
      }
    
      println(eval(Plus(Plus(Literal(1), Literal(2)), Literal(3)))(Context()))
    }
    

相关问题