2012-07-17 16 views
6

Sto tentando di scrivere un parser in Haskell usando Parsec. Attualmente ho un programma in grado di analizzareHaskell Parsec Parser per l'incontro [...]

test x [1,2,3] end 

Il codice che fa questo è dato come segue

testParser = do { 
    reserved "test"; 
    v <- identifier; 
    symbol "["; 
    l <- sepBy natural commaSep; 
    symbol "]"; 
    p <- pParser; 
    return $ Test v (List l) p 
} <?> "end" 

dove commaSep è definito come

commaSep  = skipMany1 (space <|> char ',') 

Ora c'è qualche modo per me per analizzare una dichiarazione simile, in particolare:

test x [1...3] end 

Essendo nuovo per Haskell e per Parsec, sono sicuro che c'è un modo molto semplice per farlo, di cui non sono a conoscenza. Qualsiasi aiuto sarebbe apprezzato.

Grazie ancora.

+0

Il numero di periodi deve essere costante o variabile? Gli spazi sono consentiti tra i numeri e i periodi e tra i periodi? A proposito, il tuo primo parser corrisponde a 'test x [1,, 2, ,, 3] fine'; forse non è quello che vuoi. – dflemstr

+0

Il numero di periodi dovrebbe essere costante, vale a dire [1 ... 3] dovrebbe consistere esattamente di 3 periodi per ogni caso. Gli spazi bianchi tra cui [1 ... 3] dovrebbero essere ignorati. Spero che questo chiarisca cosa sto cercando un po 'di più. –

risposta

14

Utilizzerò alcune funzioni da Control.Applicative come (*>). Queste funzioni sono utili se si desidera evitare l'interfaccia monadica di Parsec e preferire l'interfaccia applicativa, perché a mio avviso i parser diventano più facili da leggere in questo modo.

Se non si ha familiarità con le funzioni applicative di base, lasciare un commento e io le spiegherò. Puoi cercarli su Hoogle se non sei sicuro.


Come ho capito il problema, si desidera un parser per qualche struttura dati in questo modo:

data Test = Test String Numbers 
data Numbers = List [Int] | Range Int Int 

Un parser in grado di analizzare una tale struttura di dati sarebbe simile a questa (ho non compilato il codice, ma dovrebbe funzionare):

-- parses "test <identifier> [<numbers>] end" 
testParser :: Parser Test 
testParser = 
    Test <$> reserved "test" *> identifier 
     <*> symbol "[" *> numbersParser <* symbol "]" 
     <* reserved "end" 
     <?> "test" 

numbersParser :: Parser Numbers 
numbersParser = try listParser <|> rangeParser 

-- parses "<natural>, <natural>, <natural>" etc 
listParser :: Parser Numbers 
listParser = 
    List <$> sepBy natural (symbol ",") 
     <?> "list" 

-- parses "<natural> ... <natural>" 
rangeParser :: Parser Numbers 
rangeParser = 
    Range <$> natural <* symbol "..." 
     <*> natural 
     <?> "range" 
+0

Ah grazie mille, è proprio quello di cui avevo bisogno. Grazie ancora! –

+1

@VincentRusso è un sinonimo di 'fmap'. – phg

+0

Va bene, un'ultima cosa che sto ancora cercando di ottenere. Posso fare qualcosa come l <- provare (sepBy naturale virgolaSep <|> simbolo naturale "..." naturale); Solo, la mia implementazione qui non funziona, c'è qualcosa di simile che posso fare? Il tuo esempio è ottimo, ma il modo in cui il parser è attualmente implementato sembra non giocare così bene con l'esempio sopra. Grazie ancora per tutto il tuo aiuto. –

Problemi correlati