我使用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) }
但这也是不可接受的,因为它现在会“起作用”,但在未来的发展中会涉及额外的努力和锅炉板代码。
我没有测试过这段代码,因为这只是一小部分而且所有的更改都需要付出很多努力,所以首先需要专家意见。
答案 0 :(得分:2)
如果不更改a
的定义,就无法干净利落地完成此任务。 ~
组合器生成一个新的Parser
,它按顺序应用b
和c
,然后将结果(以及逻辑上的元组)组合起来并将它们作为返回结果。关键点是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)))
}
现在,如果B
在C
之前发生很多,事情会变得更加复杂。我建议,如果事情变得那么毛茸茸,那就去寻找关于Scala解析器的论文,它将介绍很多非常高级的功能。