我正在尝试在Kiama中实现一个“提交的选择”操作(以及一些以类似方式工作的其他函数)。
我想重写一个术语,只要它的一个子术语可以成功重写(其想法是,一旦你开始任何一个分支,你就是承诺的)。
目前,我可以这样做:
import org.kiama.rewriting.Rewriter
import org.junit.Test
case class B(l:L,r:L)
case class L(s:String)
class RewriteExperiment extends Rewriter {
def r1 = rule {
case L(l) if l.s == "X" => L("Did stuff")
}
def r2 = strategy {
case B(l,r) => r1(l) match {
case Some(x:L) => Some(B(x,"Avoided"))
case _ => None
}
}
implicit def s2l(s:String) : L = L(s)
}
class RewriteTest extends RewriteExperiment {
@Test
def testPruning : Unit = {
println( rewrite(r2)(B("P","b")) )
println( rewrite(r2)(B("X","b")) )
}
}因此,只有当r2可以成功地将r1应用于第一个子项时,它才会触发。
这感觉不是很Kiama-ish。我有一种感觉,我应该使用同余,但我不能从文档中弄清楚它们是如何工作的。
有没有人能推荐一种更优雅、更具Kiamaish风格的方法呢?
发布于 2013-04-08 18:38:06
同余可能是一种方法,但不幸的是,在Kiama中,它们需要一些样板。如果您想朝这个方向发展,请参阅Kiama的lambda2示例。AST.scala定义树节点类型的同余关系,ParLazySubst.scala等文件使用它们来定义策略。例如,在App (s, id)中,如果s在节点的第一个子节点上成功,则App是同余,并且App (s, id)策略在App节点上成功(id是身份策略)。
另一种选择是使用child,这是一种针对单个子对象的通用同余,您可以通过给出其编号来说明要对哪个子对象进行操作。(或者,如果您不知道它是哪个子对象,或者您希望对多个子对象进行操作,则可以使用all、one或some。)
例如,我认为下面是一种更清晰的方法来完成上面所做的事情:
def r1 =
rule {
case L (l) if l.s == "X" => L ("Did stuff")
}
def r2 =
rule {
case B (l, r) => B (l, "Avoided")
}
val r3 = (child (1, r1)) <* r2然后使用r3。
请注意,子项(...)策略在原始输入项上操作,因此我们可以使用正常排序(<*)来决定是否也将r2应用于该项。由于r2不需要了解任何关于r1的知识,因此这个解决方案更具可组合性。
https://stackoverflow.com/questions/15820362
复制相似问题