parsing scala combinators

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))