我正在尝试在 Kiama 中实现“ promise 选择”操作(以及一些以类似方式工作的其他功能)。
我想重写一个术语,前提是它的一个子术语可以成功重写(这个想法是,一旦你开始任一分支,你就 promise 了)。
目前,我可以这样做:
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 风格。我有一种感觉,我应该使用同余,但我无法从文档中弄清楚它们是如何工作的。
任何人都可以建议一种更优雅和 Kiamaish 的方式来做到这一点吗?
最佳答案
同余是一种方法,但不幸的是在凯马,它们需要一些样板。如果您想朝这个方向发展,请参阅 Kiama 的 lambda2 示例。 AST.scala 定义树节点类型的同余,ParLazySubst.scala 等文件使用它们来定义策略。例如,在 App (s, id)
中,App
是一个同余,并且 App (s, id)
策略在 上成功如果 s 在节点的第一个子节点上成功,则 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。
请注意,child (...) 策略对原始输入项进行操作,因此我们可以使用正常排序 (<*) 来决定是否也将 r2 应用于该项。该解决方案更具可组合性,因为 r2 不必了解有关 r1 的任何信息。
关于scala - 有条件地重写 Kiama/Scala 中的术语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15820362/