簡體   English   中英

什么是動態組合Scala的解析器組合器的功能?

[英]What would be the function to dynamically combine Scala's parser combinators?

我正在尋找一個動態組合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功能。 無論我采用哪種方式,它似乎都充滿了我現在無法思考如何解決的問題。 例如,如何構建折疊的初始解析器? 我試圖嘗試各種foldLeftreduceLeft結構,但似乎無法完全實現。

我正在使用Scala 2.11。 有任何想法嗎?

這是一個排序操作Scalaz提供了一個快捷方式(通常你不需要使用Scalaz的顯式實例定義樣板,但這是一個特例 ):

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實例在其他情況下可能會有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM