[Haskell-beginners] Parsing

Mike Houghton mike_k_houghton at yahoo.co.uk
Sat Mar 19 13:19:36 UTC 2016


Hi, 

Just to recap I wanted to parse name:value pairs where some pairs are mandatory and some are not.
eg 
   //these are mandatory
   location : /user/local
   target    : /x/y
 
  //these are optional 
  copyTo :  /a/b
  trace    : bla blah ,,, 
  undo    : etc etc


so I made 
data Item    = Item    (Name, Value) deriving (Show)
where Name, Value are strings and made a parser for it.

-- KeyWordItemParser
kwip :: String -> Parser Item
kwip keyWord = do
  spaces
  name <- string keyWord
  spaces
  char ':'
  spaces
  val  <-  itemValue
  spaces
  return $ Item (name, val)
 
I made the mandatory of fixed order and hence easy to parse.
For the optional I ended up defining a fixed  order in which they  can appear if indeed they do appear. 
So, for example,  ‘copyTo' has to come before ‘trace’

This allowed code like 

many $ kwip “copyTo"
many $ kwip “trace"
many $ kwip “undo"

which of course may result in duplicates that are later flagged as errors in post parsing validation. This validation step was needed 
anyway for other checking so a bit more  was sort of ok.

Pragmatically speaking It works ok but I’m not really happy with it. I’d really like to not have to enforce order. 

What I have been considering but have not yet been able to articulate in Haskell is, for parsing the optionals in any order, is to create a list of parsers and apply whilst removing parsers from the list. i.e. in pseudo code…
Try to parse 
A : w 
B : x 
C : y 
D : z  
in any order
 
 parserList  = [kwip A, kwip B, kwip C, kwip D]

parse list text = do
  parserList empty? then done
  try a  parser from parserList until one works - if none work then done (or error)
 if one worked accumulate result
 remove succesful parser from parserList then call again

Any advice on how to write this in Haskell would be appreciated. 

Many thanks
Mike
 
 


> On 6 Mar 2016, at 10:17, Francesco Ariis <fa-ml at ariis.it> wrote:
> 
> On Sun, Mar 06, 2016 at 09:54:34AM +0000, Mike Houghton wrote:
>> Hi Francesco,
>> Quick response! Thanks.
>> 
>> I see, so would it reduce to something like?
>> many itemValue 
>> 
>> and originally I was thinking the data structure that it would parse
>> into would be 
>> 
>> data Module = Module {— some record structure—}
>> 
>> but now it would be roughly like…
>> 
>> type Entry = (String, String)
>> 
>> data Module  = Module [Entry]
>> 
>> Thanks
> 
> Yes, it would lead to some kind of (YourType, String) association list.
> If you are more interested in a datatype with records I see two
> ways of achieving it:
> 
>    a. a function `[(YrType, String)] -> RecordsData` (not so
>       pretty but doable, also you can check for well-formedness here)
>       (Using a sum type YrType is in my opinion better than plain
>       Strings as it catches some more errors at compile time).
> 
>    b. directly via parsing, using `optionMaybe` and glue.
>       Depending on how your input is structured this may or may not be
>       more hairy (can name and source appear after an optional tag?
>       What about duplicated tags? etc.).
>       In its simplest form you can use a succinct applicative-style,
>       but the castle crumbles if want more.
> 
> 
> See which fits better (I suspect a.), play with it and report
> back; parsing has never been an elegant business!
> 
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners



More information about the Beginners mailing list