2013-04-04 57 views
2

我想在凯马实现一个“承诺选择”操作(以及其他一些以类似方式工作的函数)。在凯马/斯卡拉有条件地重写术语

我想重写一个术语,如果其中一个子项可以被成功重写(想法是一旦你开始任何一个分支,你承诺)。

目前,我能做到这样的:

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向第一subterm成功。

这并不觉得很开基马。我有一种感觉,我应该使用congruences,但我无法弄清楚他们是如何从文档中工作的。

任何人都可以建议一个更优雅和Kiamaish的方式来做到这一点?

回答

3

congruences将是一种方式,但不幸的是,在凯马他们需要一些样板。如果你想朝那个方向走,请参阅Kiama的lambda2例子。 AST.scala为树节点类型定义了一致性,ParLazySubst.scala等文件使用它们来定义策略。例如,在App (s, id)中,如果在节点的第一个子节点上成功(id是身份策略),则App是一致的并且App (s, id)策略在App节点上成功。

另一种方法是使用child,它对于单个孩子来说是一种通用的一致性,你可以通过给出它的数量来说明你想操作哪个孩子。 (或者,如果你不知道它是哪个孩子或者你想在一个以上的孩子进行操作,您可以使用allone,或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的任何信息。