Haskell Parsec and unordered properties

I am trying to use Parsec to parse something like this:

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

I implement the iCalendar specification, and each of them has a name: parameters: value triplet, very similar to how XML has a name: attributes: content triplet. Infact you can very easily convert iCalendar to XML format (I think I can’t see the benefits).

My point is that the parameters should not be in any order at all, and each parameter can have a different type. One parameter can be a string, and the other can be a numerical identifier for another element. They have no similarities yet, in the end, I want to correctly place them in the correct entry fields for any “SomeObjectInstance” that I wanted the parser to return. How can I do this (or can you give me an example of where someone should parse data like this)?

Thank you, I know that my question is probably a little confused, but it reflects my level of understanding of what I need to do.

Edit : I tried to avoid getting the expected result (because it is big, and not because it is hidden), but here is an example of the input file (from Wikipedia):

GET STARTED: VCALENDAR
VERSION: 2.0
PRODID: - // hacksw / handcal // NONSGML v1.0 // EN
GET STARTED: VEVENT
UID: uid1@example.com
DTSTAMP: 19970714T170000Z
ORGANIZER; CN = John Doe: MAILTO: john.doe@example.com
DTSTART: 19970714T170000Z
DTEND: 19970715T035959Z
SUMMARY: Bastille Holiday Party
END: VEVENT
END: VCALENDAR

As you can see, it contains one VEvent inside VCalendar, I created data structures that represent them here .

I'm trying to write a parser that parses this type of file in my data structures, and I'm stuck on a bit where I need to handle properties coming in any order with any type; date, time, int, string, uid, ect. I hope this makes sense without repeating the entire iCalendar specification.

+6
properties haskell parsec icalendar parser-generator
source share
2 answers

Parsec has the Parsec.Perm module for parsing unordered, but linear (that is, at the same level in the syntax tree) elements, such as attribute tags in XML files.

Unfortunately, the Perm module is mostly undocumented. The best reference is the Parsing Permutation Phrases document referenced by the Haddock document page, but even this is basically a description of the method, not how to use it.

+6
source share

So, between BEGIN:VEVENT and END:VEVENT you have many key pairs. So write a keyValuePair rule that returns (key, value) . Now inside the rule for VEVENT you do many KeyValuePair to get a list of pairs. After you have done this, you use the fold to populate the VEVENT record with the given values. In the function that you give to reset, you use pattern matching to find out in which field the value is stored. You use the VEvent entry as the starting value for the battery, where the additional fields are set to Nothing . Example:

 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} 

... and so on. Do the same for the other components.

Edit: here is the executable code for folding:

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

Output:

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

Please note that when compiling this will result in a warning. To avoid the warning, explicitly initialize all optional undefined fields.

+1
source share

All Articles