Scala кастом отменить с дженериками
Я хотел бы сжать мой оценщик благодаря пользовательской универсальной функции unapply, которая оценивает аргумент и возвращает значение в случае успеха.
Но это не с ошибкой error: not found: type Eval
Есть ли способ достичь этого? Я посмотрел на теги типа, неявные преобразования для неприменимых методов, но не вижу, как я мог бы интегрировать их в эту проблему. Как правильно определить Eval?
Тест объекта { case class Context() черта Expr черта Literal[T] расширяет Expr{ значение по умолчанию: T } case-класс IntLiteral (значение: Int) расширяет литерал [Int] case-класс StringLiteral(значение: Int) расширяет Literal[Int] case case Plus(e: Expr, f: Expr) расширяет Expr object Eval { // Здесь я хочу, чтобы волшебство не применялось для оценки выражения. def unapply[T](e: Expr)(неявный gctx: Context): Option[T] = { eval(e) match { case e: Literal[T] => Some(e.value) case _ => Нет } } } def eval(e: Expr)(неявный c: Context): Expr = e match { case Plus(Eval[Int](i), Eval[Int](j)) => IntLiteral(i+j) // Здесь происходит сбой. case IntLiteral(i) => e case StringLiteral(s) => e } Eval (Плюс (Плюс (IntLiteral(1),IntLiteral(2)),IntLiteral(3)))(контекст ()) }
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()))
}