2010-09-14 27 views
6

Estoy tratando de utilizar Parsec para analizar algo como esto:Haskell Parsec y propiedades no ordenadas

property :: CharParser SomeObject 
property = do 
    name 
    parameters 
    value 
    return SomeObjectInstance { fill in records here } 

Me estoy poniendo en práctica la especificación de iCalendar y en cada que hay un nombre: parámetros: valor de triplete, muy parecido la forma en que XML tiene un nombre: atributos: contenido triplete. Infact you could very easily convert an iCalendar into XML format (pensé que realmente no puedo ver las ventajas).

Mi punto es que los parámetros no tienen que venir en orden alguno y cada parámetro puede tener un tipo diferente. Un parámetro puede ser una cadena mientras que el otro es la identificación numérica de otro elemento. Es posible que todavía no compartan ninguna similitud. Al final, quiero ubicarlos correctamente en los campos de registro correctos para cualquier 'SomeObjectInstance' que desee que el analizador devuelva. ¿Cómo hago este tipo de cosas (o puede señalarme un ejemplo de dónde alguien tuvo que analizar datos como este)?

Gracias, sé que mi pregunta es probablemente un poco confusa, pero eso refleja mi nivel de comprensión de lo que debo hacer.

Editar: yo estaba tratando de evitar dar el resultado esperado (porque es grande, no porque se oculta) pero aquí es un ejemplo de un archivo de entrada (de Wikipedia):

COMENZAR : VCALENDAR
VERSION: 2.0
PRODID: - // hacksw/handcal // NONSGML v1.0 // EN
BEGIN: VEVENT
UID: [email protected]
DTSTAMP: 19970714T170000Z
ORGANIZADOR; CN = John Doe: mailto: [email protected]
DTSTART: 19970714T170000Z
DTEND: 19970715T035959Z
RESUMEN: partido del día Bastille
END: VEVENT
END: VCALENDAR

Como puede ver, contiene un VEvent dentro de un VCalendar, hice data structures that represent them here.

Estoy tratando de escribir un analizador sintáctico que analiza ese tipo de archivo en mis estructuras de datos y estoy atascado en el bit donde necesito manejar las propiedades que vienen en cualquier orden con cualquier tipo; fecha, hora, int, cadena, uid, etc. Espero que tenga más sentido sin repetir toda la especificación de iCalendar.

+0

No estoy seguro de lo que estás preguntando. ¿Podría dar un ejemplo de una posible entrada y el resultado esperado? – sepp2k

+0

Di más información y espero que tenga más sentido ahora, usted ha esperado la entrada y las estructuras de datos que estoy tratando de completar con el analizador. Ahora solo estoy tratando de descubrir cómo hacerlo con parsec. –

Respuesta

6

Parsec tiene el módulo Parsec.Perm precisamente para analizar elementos desordenados pero lineales (es decir, en el mismo nivel en el árbol de sintaxis) como etiquetas de atributos en archivos XML.

Desafortunadamente, el módulo de Perm está prácticamente sin documentar. La mejor referencia es el documento Parsing Permutation Phrases, que se refiere a la página de Haddock doc, pero incluso eso es en gran parte una descripción de la técnica en lugar de cómo usarla.

+0

Wow, tienes razón, ese es un excelente consejo. Voy a leer sobre eso tan pronto como pueda y si resulta ser exactamente lo que necesito, entonces incluso puedo escribir una publicación en el blog sobre eso. –

+0

Hay dos ejemplos en la sección 5 de Analizar frases de permutación.El manual original de Parsec también tiene un ejemplo trivial: podría ser útil ya que los nombres del combinador difieren entre Parsec y el documento PPP. El manual de Parsec está disponible aquí: http://legacy.cs.uu.nl/daan/parsec.html –

+1

Para cualquier otra persona que busque una solución a este tipo de problema, Robert sí escribió una publicación en el blog sobre el tema: http://robertmassaioli.wordpress.com/2010/09/15/unordered-parsing-in-parsec/ Lamentablemente, el software del blog parece estar eliminando ciertos caracteres. He agregado los bits faltantes y los he publicado aquí: http://hpaste.org/46655/simple_example_of_parsec_perm Gracias por escribir un ejemplo simple Robert. –

1

Ok, así que entre BEGIN:VEVENT y END:VEVENT, tiene muchos pares de valores clave. Por lo tanto, escriba una regla keyValuePair que devuelva (key, value). Ahora dentro de la regla para VEVENT, haga many KeyValuePair para obtener una lista de pares. Una vez hecho esto, usa un doblez para completar un registro de VEVENT con los valores dados. En la función que das para doblar, utilizas la coincidencia de patrones para averiguar en qué campo almacenar el valor. Como valor inicial para el acumulador, usa un registro VEvent donde los campos opcionales están configurados en Nothing. Ejemplo:

pairs <- many keyValuePairs 
vevent = foldr f (VEvent {sequence = Nothing}) pairs 
    where f ("SUMMARY", v) ve = ve {summary = v} 
      f ("DSTART", v) ve = ve {dstart = read v} 

... y así sucesivamente. Haz lo mismo para los otros componentes.

Editar: Aquí hay un código de ejemplo ejecutable para el pliegue:

data VEvent = VEvent { 
     summary :: String, 
     dstart :: String, 
     sequenceSt :: Maybe String 
     } deriving Show 

vevent pairs = foldr f (VEvent {sequenceSt = Nothing}) pairs 
    where f ("SUMMARY", v) ve = ve {summary = v} 
      f ("DSTART", v) ve = ve {dstart = v} 
      f ("SEQUENCEST", v) ve = ve {sequenceSt = Just v} 

main = do print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu")] 
      print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu"), ("SEQUENCEST", "lili")] 

Salida:

VEvent {summary = "lala", dstart = "lulu", sequenceSt = Nothing} 
VEvent {summary = "lala", dstart = "lulu", sequenceSt = Just "lili"} 

Tenga en cuenta que esto producirá una advertencia cuando se compila. Para evitar la advertencia, inicialice todos los campos no opcionales al undefined explícitamente.

+0

Esto es similar a lo que pensé al principio, pero ¿cómo se puede decidir qué es 'cero' por ejemplo? Usted dio el 'cero' como 'VEvent {sequence = Nothing}', pero ¿y si la estructura es más complicada como una de las que hice, qué pasa si tiene un montón de campos enteros que deben ser configurados y no lo hace? Quiero hacer que cada campo de registro sea Tal vez. ¿Puedes hacer registros pieza por pieza con múltiples campos obligatorios que no das al principio? (Avíseme si necesito describir mejor esta nueva pregunta y trataré de proporcionar un ejemplo de código) –

+0

@Robet: como dije, inicialice las opcionales para 'Nothing'. Los otros no necesitan inicializarse en absoluto. Si no hubiera opciones opcionales, 'Vevent {}' sería un valor de inicio perfectamente correcto (o podría establecer explícitamente cada valor no opcional en indefinido para evitar recibir una advertencia, pero supongo que eso sería tedioso con muchos campos) . – sepp2k

+0

¿Esto falla para mí sin embargo? http://pastie.org/1157529 –

Cuestiones relacionadas