简体   繁体   English

Scala:将组合器解析器中的parseresult(〜)展平为List?

[英]Scala: Flatten the parseresult (~) from combinators parser into List?

I wrote some parser from combinatory library. 我从组合库中编写了一些解析器。 I want a generic function that transform any size of nest ~ into a list. 我想要一个泛型函数,将任何大小的nest变换成一个列表。 How to do this ? 这个怎么做 ?

Here is my example of parser I use (my real parser has a very long chain ~ so I want to avoid my current solution which is in comment below). 这是我使用的解析器的例子(我真正的解析器有一个非常长的链〜所以我想避免我现在的解决方案,这在下面的评论中)。

object CombinatorParser extends RegexParsers {

  lazy val a = "a"
  lazy val b = "b"
  lazy val c = "c"
  lazy val content = a ~ b ~ c // ^^ {case a~b => a::b::c::Nil work but I want something more general that work for any ~ length.
}

object CombinatorTesting {

  def main(args:Array[String]) {
    val testChar = "abc"
    val output = CombinatorParser.parseAll(CombinatorParser.content, testChar)
    println(output) // ((a~b)~c) but I want List(a,b,c)
  }
}

This is a good (and fairly simple) application for the kind of generic programming techniques exemplified in shapeless . 这是一种很好的(并且相当简单)应用程序,适用于无形中示例的通用编程技术。

Given your definition, 根据你的定义,

object CombinatorParser extends RegexParsers {
  lazy val a = "a"
  lazy val b = "b"
  lazy val c = "c"
  lazy val content = a ~ b ~ c
}

We can recursively define a type class that will flatten it's results as follows, 我们可以递归地定义一个类型类,它会将它的结果展平如下,

import CombinatorParser._

First we define a trait which (abstractly) flattens an arbitrary match M to a List[String] , 首先,我们定义一个特征(抽象地)将任意匹配M平为List[String]

trait Flatten[M] extends (M => List[String]) {
  def apply(m : M) : List[String]
}

Then we provide type class instances for all the shapes of M that we're interested in: in this case, String , A ~ B and ParseResult[T] (where A , B and T are all types for which there are Flatten instances), 然后我们为我们感兴趣的M所有形状提供类型类实例:在这种情况下, StringA ~ BParseResult[T] (其中ABT都是Flatten实例的所有类型) ,

// Flatten instance for String
implicit def flattenString = new Flatten[String] {
  def apply(m : String) = List(m) 
}

// Flatten instance for `A ~ B`. Requires Flatten instances for `A` and `B`. 
implicit def flattenPattern[A, B]
  (implicit flattenA : Flatten[A], flattenB : Flatten[B]) =
    new Flatten[A ~ B] {
      def apply(m : A ~ B) = m match {
        case a ~ b => flattenA(a) ::: flattenB(b)
      } 
}

// Flatten instance for ParseResult[T]. Requires a Flatten instance for T.
implicit def flattenParseResult[T]
  (implicit flattenT : Flatten[T]) = new Flatten[ParseResult[T]] {
    def apply(p : ParseResult[T]) = (p map flattenT) getOrElse Nil 
}

Finally we can define a convenience function to simplify applying Flatten instances to parse results, 最后,我们可以定义一个便捷函数来简化应用Flatten实例来解析结果,

def flatten[P](p : P)(implicit flatten : Flatten[P]) = flatten(p)

And now we're ready to go, 现在我们准备好了,

val testChar = "abc"
val output = parseAll(content, testChar)
println(output)          // ((a~b)~c) but I want List(a, b, c)

val flattenedOutput = flatten(output)
println(flattenedOutput) // List(a, b, c)

If you prefer a solution without generic programming... 如果您更喜欢没有通用编程的解决方案......

  def flatten(res: Any): List[String] = res match {
    case x ~ y => flatten(x) ::: flatten(y)
    case None => Nil
    case Some(x) => flatten(x)
    case x:String => List(x)
  }

  val testChar = "abc"
  val output = CombinatorParser.parseAll(CombinatorParser.content, testChar).getOrElse(None)
  println(flatten(output))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM