我正在寻找动态组合Scala Parser Combinators的功能。例如,如果我想静态地做,我可以写:
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combinedDirective: Parser[List[String]] =
aDirective ~ bDirective ^^ { case a ~ b => List(a, b) }
然而,为了生成解析器的组合,我希望能够动态地执行此操作,而不是静态编码。
例如:
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
def combine(parsers: List[Parser[T]): Parser[List[T]] = ???
我想我需要从解析器列表转到结果列表的解析器。所以我试图为名为combine
的函数编写签名。
目前我无法弄清楚如何实现combine
功能。无论我采用哪种方式,它似乎都充满了我现在无法思考如何解决的问题。例如,如何构建折叠的初始解析器?我试图尝试各种foldLeft
和reduceLeft
构造,但似乎无法完全实现。
我正在使用Scala 2.11。有什么想法吗?
答案 0 :(得分:3)
这是sequencing operation,Scalaz提供了一种快捷方式(通常您不需要使用Scalaz的显式实例定义样板,但是this is a special case):
import scala.util.parsing.combinator.RegexParsers
import scalaz._, Scalaz._
object MyParser extends RegexParsers {
implicit val pm = std.util.parsing.combinator.parser.parserMonad(this)
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combine[T](parsers: List[Parser[T]]): Parser[List[T]] = parsers.sequenceU
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
}
然后:
scala> MyParser.parseAll(MyParser.combinedDirective, "ab")
res0: MyParser.ParseResult[List[String]] = [1.3] parsed: List(a, b)
您也可以使用折叠自己定义:
import scala.util.parsing.combinator.RegexParsers
object MyParser extends RegexParsers {
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combine[T](parsers: List[Parser[T]]): Parser[List[T]] =
parsers.foldRight(success(List.empty[T])) {
case (p, acc) => for {
pRes <- p
accRes <- acc
} yield pRes :: accRes
}
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
}
它的工作方式完全一样。诀窍就是让基础正确 - 它需要是一个解析器,总是以空列表作为其值成功。
更新:如果您正在定义一个类而不是一个对象,那么上面的Scalaz方法将无法正常工作(出于一些奇怪的原因 - 简而言之this
并非如此足够稳定)。不过,您可以非常轻松地定义自己的monad实例:
class MyParser extends RegexParsers {
implicit val pm = new Monad[Parser] {
def point[A](a: => A): Parser[A] = success(a)
def bind[A, B](fa: Parser[A])(f: A => Parser[B]): Parser[B] = fa flatMap f
}
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combine[T](parsers: List[Parser[T]]): Parser[List[T]] = parsers.sequenceU
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
}
你实际上不需要monad实例来使用sequence
,只是一个应用程序仿函数,但是定义实际上更方便一点,monad实例在其他情况下可能会有用。