Scala:解析转换问题

时间:2010-09-01 20:33:08

标签: parsing scala

我使用Scala的组合子解析器如下:

def a = b ~ c ^^ { case x ~ y => A(x,y) }
def b = ... { B() }
def c = ... { C() }

现在我有一个功能更改,在先前已解析的B的引用解析为val中的C。所以C的构造函数就像:

C(ref:B)

我可以想象,实现这一目标的唯一方法是通过在解析B之间将解析后的def c对象实例分配给a来实现脏补丁工作。如下所示:

var temp:B = null

def a = ( b ^^ { case x => temp = x } )
        ~ c(temp) ^^ {case x ~ y => A(x,y} )

这样做有标准,干净的方法吗? a的定义不能被破坏,它在其余代码的许多地方使用。

另一个解决方案是使用var代替val,并遵循:

 def a = (b ~ c ) ^^ { case x ~ y => y.ref = c ; A(x,y) }

但这也是不可接受的,因为它现在会“起作用”,但在未来的发展中会涉及额外的努力和锅炉板代码。

我没有测试过这段代码,因为这只是一小部分而且所有的更改都需要付出很多努力,所以首先需要专家意见。

3 个答案:

答案 0 :(得分:2)

如果不更改a的定义,就无法干净利落地完成此任务。 ~组合器生成一个新的Parser,它按顺序应用bc,然后将结果(以及逻辑上的元组)组合起来并将它们作为返回结果。关键点是c的应用不是b输出的函数,因此在b的应用中无法获得c的结果。 1}}。

我要做的是添加一个新的组合器,它可以满足您的需求。我并不觉得名字特别有创意,但我认为这应该给你一个粗略的想法:

implicit def cleverParserSyntax[A](left: Parser[A]) = new {
  def ~%[B](right: A => Parser[B]): Parser[A ~ B] = for {
    lr <- left
    rr <- right(lr)
  } yield new ~(lr, rr)
}

def a = b ~% c ^^ { case x ~ y => A(x,y) }
def b = ... { B() }
def c(res: B) = ... { C(res) }

答案 1 :(得分:2)

我不确定我是否正确理解了问题,但如果C依赖于B,为什么不以功能方式表达呢?

case class B(...)
case class C(b: B, ...)
case class A(b: B, c: C)

def b: Parser[B] = ... ^^ { B(...) }
def c: Parser[B => C] = ... ^^ { C(_, ...) }
def a: Parser[A] = b ~ c ^^ {  A(b, c(b)) }

通过这种方式,您的问题得以解决,您可以明确地以简洁的方式表达您的依赖关系。

答案 2 :(得分:1)

我会这样做:

case class B(x: String)
case class C(b: B, x: String)       
case class A(b: B, c: C)

class MyParser extends RegexParsers {               
  def a = b >> c ^^ { case x ~ y => A(x, y) }       
  def b = "\\w+".r ^^ B                             
  def c(b: B) = "\\d+".r ^^ (x => new ~(b, C(b, x)))
}

现在,如果BC之前发生很多,事情会变得更加复杂。我建议,如果事情变得那么毛茸茸,那就去寻找关于Scala解析器的论文,它将介绍很多非常高级的功能。