Scala:为案例类动态生成匹配子句 [英] Scala: Dynamically generating match clauses for case classes

查看:102
本文介绍了Scala:为案例类动态生成匹配子句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在一组条件-动作"规则中使用Scala模式匹配的功能.这些规则不是事先已知的,而是根据某些复杂的条件在运行时生成的. 算法生成机制可以被认为是完全独立的,并且不是该问题的一部分,该问题与如何通过Scala反射/拟引用表达出来有关.

I want to use the power of Scala's pattern matching within a set of `condition-action' rules. These rules are not known in advance, but rather are generated at runtime according to some complex critera. The algorithmic generation mechanism can be considered as a completely separate and is not part of this question, which is concerned with how to express this via Scala reflection/quasiquotes.

具体来说,我希望在运行时生成案例定义(一般形式为case v0@x(v1,_,v2): X => f(v1,v2)).

Concretely, I'm looking to generate case definitions (of the general form case v0@x(v1,_,v2): X => f(v1,v2)) at runtime.

对于通过运行时生成的某些字符串,可能可以通过toolBox.parse(str)进行此操作.但是,如果可能的话,似乎需要引入比这更大的类型安全性:

It is presumably possible to do this via toolBox.parse(str) for some string that is generated at runtime. However, if possible it would seem desirable to incorporate a greater degree of type-safety than this:

更具体地说,我希望case defs与术语(Term,Var(name: Char),Lit(value:Int),Group(a: Term,b: Term,c: Term))的密封case类层次结构匹配.

More specifically, I want the case defs to match against a sealed case class hierarchy of Terms (Term,Var(name: Char),Lit(value:Int),Group(a: Term,b: Term,c: Term)).

例如,生成的case def通常将返回v0,v1,v2的某些函数,无函数,部分或全部:

For example, the generated case def would in general, return some function of none, some or all of v0,v1,v2:

  t match {
    case v0@Group(v1@_,v2@Var('a')) => Group(v2,v0,Group(v1,Var('z'),Lit(17))) // etc
  }

我正在尝试对给出的

I'm attempting to follow through on the description of quasiquotes for case defs given here, but the syntax is rather mind-bending (and eclipse with Scala 2.11 refuses to show me the types), so below is as far as I've got. My specific questions are embedded in the code:

def dynamicMatch(condition: SomeType, action: SomeType, tb: ToolBox)
(t: Term): Option[Term] = {

  // Q1. What type should condition and action be for maximum
  // typesafety in the calling code? Symbols? Quasiquotes? 
  // Would they best be combined into a single actual CaseDef?

  // This is obviously a hardcoded placeholder expression, in general:
  // Q2. How to bind in t, condition and action?
  val q"$expr match { case ..$cases }" =
    q"foo match { case _ : Term => Some(expr) case _ => None }"

  val cq"$pat1 => $body1" :: cq"$pat2 => $body2" :: Nil = cases

  // Q3. how should this be invoked to return the desired result?
  ???
}

推荐答案

有一个

There's a shapeless example that builds a function invocation with the purpose of getting the toolbox to select a typeclass based on runtime types.

您还希望动态地构建逻辑,但是在准报价方面遇到困难.

You also want to build the logic dynamically, but you're having difficulty with quasiquoting.

这可以做些什么:

// Some classes
sealed trait Term
case class Lit(value: Int) extends Term
case class Group(a: Term, b: Term) extends Term

// Build a function that hooks up patterns to other expressions
  def stagedTermFunction(t: Term): Option[Term] = {
    // add lits
    val tt = tq"_root_.shapeless.examples.Term"
    val lit = q"_root_.shapeless.examples.Lit"
    val grp = q"_root_.shapeless.examples.Group"
    val pat = pq"$grp($lit(x), $lit(y))"
    val add = cq"$pat => Some($lit(x + y))"
    val default = cq"_ => None"
    val cases = add :: default :: Nil
    val res = q"{ case ..$cases } : (($tt) => Option[$tt])"
    val f = evalTree[Term => Option[Term]](res)
    f(t)
  }

然后这不会爆炸:

  val t3: Term = Group(Lit(17), Lit(42))
  val Some(Lit(59)) = stagedTermFunction(t3)
  assert(stagedTermFunction(Lit(0)) == None)

如果要操作symbolOf[Group],则可能必须将sym.fullName转换为由q"name"构建的Select树;我认为某个地方有实用程序方法.

If you wanted to manipulate symbolOf[Group] you might have to convert sym.fullName to the Select tree built by q"name"; I think there's a utility method somewhere.

这篇关于Scala:为案例类动态生成匹配子句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆