构建嵌套案例类的变体

时间:2013-09-26 11:14:14

标签: scala case-class

所以我得到了这样的东西:

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中创建这些变体的最佳方法是什么? 效率会很好,但并不是真正的要求。 如果可能的话,我喜欢不使用反射。

3 个答案:

答案 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
  }