2013-04-04 55 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的任何信息。