Scala:为案例类动态生成匹配子句 [英] Scala: Dynamically generating match clauses for case classes
问题描述
我想在一组条件-动作"规则中使用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屋!