parsing - Scala: ¿Alcanzar el parseresult(~) del analizador de combinadores en List?
combinators (2)
Esta es una buena (y bastante simple) aplicación para el tipo de técnicas de programación genéricas ejemplificadas en informe .
Dada tu definición,
object CombinatorParser extends RegexParsers {
lazy val a = "a"
lazy val b = "b"
lazy val c = "c"
lazy val content = a ~ b ~ c
}
Podemos definir recursivamente una clase de tipo que aplanara los resultados de la siguiente manera,
import CombinatorParser._
Primero definimos un rasgo que (abstractamente) aplana una coincidencia arbitraria M
con una List[String]
,
trait Flatten[M] extends (M => List[String]) {
def apply(m : M) : List[String]
}
A continuación, proporcionamos instancias de clase de tipo para todas las formas de M
que nos interesan: en este caso, String
, A ~ B
y ParseResult[T]
(donde A
, B
y T
son todos los tipos para los que hay instancias de 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
}
Finalmente, podemos definir una función de conveniencia para simplificar la aplicación de instancias de Flatten
para analizar los resultados,
def flatten[P](p : P)(implicit flatten : Flatten[P]) = flatten(p)
Y ahora estamos listos para ir,
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)
Escribí un analizador de la biblioteca combinatoria. Quiero una función genérica que transforme cualquier tamaño de nido ~ en una lista. Como hacer esto ?
Aquí está mi ejemplo de analizador que uso (mi analizador real tiene una cadena muy larga ~ por lo que quiero evitar mi solución actual que está en comentario a continuación).
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)
}
}
Si prefiere una solución sin programación genérica ...
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))