2

我正在尝试在 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 的方式来做到这一点?

4

1 回答 1

3

一致性是一种方式,但不幸的是在 Kiama 他们需要一些样板。如果您想朝那个方向发展,请参阅 Kiama 的 lambda2 示例。AST.scala 为树节点类型定义同余,ParLazySubst.scala 等文件使用它们来定义策略。例如,在 中App (s, id),如果 s 在节点的第一个子节点上成功App,则App (s, id)策略在节点上成功(是恒等策略)。Appid

另一种方法是使用childwhich 是单个孩子的通用同余,您可以通过给出其编号来说明要对哪个孩子进行操作。(或者,如果您不知道它是哪个孩子,或者您想对多个孩子进行操作,您可以使用allonesome。)

例如,我认为以下是执行上述操作的更清晰方法:

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

于 2013-04-08T10:38:06.067 回答