3

引数を評価し、成功した場合は値を返すカスタム汎用 unapply 関数のおかげで、エバリュエーターを要約したいと思います。

しかし、これはエラーで失敗しますerror: not found: type Eval

これを達成する方法はありますか?unapply メソッドの暗黙的な変換であるtypetagsを見てきましたが、この問題にそれらを統合する方法がわかりません。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())
}
4

1 に答える 1

2

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()))
}
于 2016-07-28T13:20:34.217 に答える