所以我得到了这样的东西:
abstract class Term
case class App(f:Term,x:Term) extends Term
case class Var(s:String) extends Term
case class Amb(a:Term, b:Term) extends Term //ambiguity
一个术语可能如下所示:
App(Var(f),Amb(Var(x),Amb(Var(y),Var(z))))
所以我需要的是Amb类所指示的所有变体。 这用于表示模糊的解析林,我想键入检查每个可能的变体并选择正确的变体。 在这个例子中,我需要:
App(Var(f),Var(x))
App(Var(f),Var(y))
App(Var(f),Var(z))
在scala中创建这些变体的最佳方法是什么? 效率会很好,但并不是真正的要求。 如果可能的话,我喜欢不使用反射。
答案 0 :(得分:5)
Scala提供模式匹配解决这些问题。解决方案看起来像:
def matcher(term: Term): List[Term] = {
term match {
case Amb(a, b) => matcher(a) ++ matcher(b)
case App(a, b) => for { va <- matcher(a); vb <- matcher(b) } yield App(va, vb)
case v: Var => List(v)
}
}
答案 1 :(得分:4)
使用遍历树的递归函数并扩展歧义,您可以非常干净地执行此操作:
sealed trait Term
case class App(f: Term, x: Term) extends Term
case class Var(s: String) extends Term
case class Amb(a: Term, b: Term) extends Term
def det(term: Term): Stream[Term] = term match {
case v: Var => Stream(v)
case App(f, x) => det(f).flatMap(detf => det(x).map(App(detf, _)))
case Amb(a, b) => det(a) ++ det(b)
}
请注意,我使用的是密封特征而不是抽象类,以便利用编译器检查穷举的能力。
按预期工作:
scala> val app = App(Var("f"), Amb(Var("x"), Amb(Var("y"), Var("z"))))
app: App = App(Var(f),Amb(Var(x),Amb(Var(y),Var(z))))
scala> det(app) foreach println
App(Var(f),Var(x))
App(Var(f),Var(y))
App(Var(f),Var(z))
如果您可以更改Term
API,则可以或多或少地在那里添加def det: Stream[Term]
方法。
答案 2 :(得分:0)
因为我的抽象语法相当大(我有多个),所以我和Kiama一起试试运气。 所以这里是Travis Brown和Mark与Kiama发布的版本。
它不漂亮,但我希望它有效。欢迎提出意见。
def disambiguateRule: Strategy = rule {
case Amb(a: Term, b: Term) =>
rewrite(disambiguateRule)(a).asInstanceOf[List[_]] ++
rewrite(disambiguateRule)(b).asInstanceOf[List[_]]
case x =>
val ch = getChildren(x)
if(ch.isEmpty) {
List(x)
}
else {
val chdis = ch.map({ rewrite(disambiguateRule)(_) }) // get all disambiguate children
//create all combinations of the disambiguated children
val p = combinations(chdis.asInstanceOf[List[List[AnyRef]]])
//use dup from Kiama to recreate the term with every combination
val xs = for { newchildren <- p } yield dup(x.asInstanceOf[Product], newchildren.toArray)
xs
}
}
def combinations(ll: List[List[AnyRef]]): List[List[AnyRef]] = ll match {
case Nil => Nil
case x :: Nil => x.map { List(_) }
case x :: xs => combinations(xs).flatMap({ ys => x.map({ xx => xx :: ys }) })
}
def getChildren(x: Any): List[Any] = {
val l = new ListBuffer[Any]()
all(queryf {
case a => l += a
})(x)
l.toList
}