使用scala中的解析器组合器创建递归数据结构

anc*_*ite 6 tree parsing scala parser-combinators

我是scala的初学者,在S99上尝试学习scala.其中一个问题涉及从字符串转换为树数据结构.我可以"手动"完成它,我也想看看如何使用Scala的解析器组合器库来实现它.

树的数据结构是

sealed abstract class Tree[+T]
case class Node[+T](value: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
  override def toString = "T(" + value.toString + " " + left.toString + " " + right.toString + ")"
}
case object End extends Tree[Nothing] {
  override def toString = "."
}
object Node {
  def apply[T](value: T): Node[T] = Node(value, End, End)
}    
Run Code Online (Sandbox Code Playgroud)

输入应该是一个字符串,如下所示: a(b(d,e),c(,f(g,)))

我可以用类似的东西来解析字符串

trait Tree extends JavaTokenParsers{
  def leaf: Parser[Any] = ident
  def child: Parser[Any] = node | leaf | ""
  def node: Parser[Any] = ident~"("~child~","~child~")" | leaf 
}
Run Code Online (Sandbox Code Playgroud)

但是如何使用解析库来构建树?我知道我可以^^用来将一些字符串转换为整数.我的困惑来自于在创建实例时需要"知道"左右子树Node.我怎么能这样做,或者这是我想要做些不同的事情的标志?

我最好采取解析器返回的东西((((((a~()~(((((b~()~d)~,)~e)~)))~,)~(((((c~()~)~,)~(((((f~()~g)~,)~)~)))~)))~))对于上面的示例输入),并根据它构建树,而不是使用像^^^^^直接构建树的解析器运算符?

Tra*_*own 5

可以干净利落地完成这项任务^^,而且你非常接近:

object TreeParser extends JavaTokenParsers{
  def leaf: Parser[Node[String]] = ident ^^ (Node(_))
  def child: Parser[Tree[String]] = node | leaf | "" ^^ (_ => End)
  def node: Parser[Tree[String]] =
    ident ~ ("(" ~> child) ~ ("," ~> child <~ ")") ^^ {
      case v ~ l ~ r => Node(v, l, r)
    } | leaf
}
Run Code Online (Sandbox Code Playgroud)

现在:

scala> TreeParser.parseAll(TreeParser.node, "a(b(d,e),c(,f(g,)))").get
res0: Tree[String] = T(a T(b T(d . .) T(e . .)) T(c . T(f T(g . .) .)))
Run Code Online (Sandbox Code Playgroud)

在我看来,解决这类问题的最简单方法是使用您想要的结果键入解析器方法,然后添加适当的映射操作,^^直到编译器满意为止.