Domanda

I sono la conversione del codice Haskell funzionante che utilizza Parsec utilizzare invece Attoparsec nella speranza di ottenere una migliore performance. Ho fatto i cambiamenti e tutto viene compilato ma il mio parser non funziona correttamente.

Io sono l'analisi di un file che si compone di vari tipi di record, uno per riga. Ognuno dei miei singole funzioni per l'analisi di un record o commento funziona correttamente, ma quando provo a scrivere una funzione di compilare una sequenza di record parser restituisce sempre un risultato parziale, perché si aspetta più input.

Queste sono le due principali variazioni che ho provato. Entrambi hanno lo stesso problema.

items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine

Per questo secondo ho cambiato il record / commento parser di consumare i caratteri di fine linea.

items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput

C'è sbagliato nulla con il mio approccio? C'è qualche altro modo per ottenere ciò che sto cercando?

È stato utile?

Soluzione

Ho eseguito in questo problema prima e la mia comprensione è che è causato dal modo in cui funziona <|> nella definizione di sepBy:

sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
    where scan = liftA2 (:) p ((s *> scan) <|> pure [])

Questo sposterà solo per una volta pure [] (s *> scan) ha fallito, che non accadrà solo perché sei alla fine dell'input.

La mia soluzione è stata solo per chiamare feed con una ByteString empty sul Result restituito da parse. Questo potrebbe essere una specie di hack, ma sembra anche di essere come offerte attoparsec-iteratee con il tema:

f k (EOF Nothing)  = finalChunk $ feed (k S.empty) S.empty

Per quanto posso dire questo è l'unico motivo che attoparsec-iteratee lavora qui e pianura vecchio parse non.

Altri suggerimenti

Se si scrive un parser attoparsec che consuma più input possibili prima di fallire, è necessario indicare il risultato parziale prosecuzione quando hai raggiunto la fine del vostro input.

È dare abbastanza poche informazioni che è il motivo per cui penso che sia difficile dare un buon aiuto. Tuttavia ci sono un paio di commenti vorrei dare:

  • Forse il parser non si rendono conto che l'ingresso è fatto e si cerniere su entrambi ottenere un EOL o di ottenere un altro record. Quindi chiede un risultato parziale. Provare a caricare l'equivalente di EOL nella speranza che costringe.
  • Non riesco a ricordare il codice, ma utilizzando l'istanza alternativa potrebbe essere dannoso per l'analisi delle prestazioni. Se questo è il caso, si consiglia di caso sulla commento e recordTypes.
  • Io uso di cereali per un sacco di analisi binario e che è anche estremamente veloce. attoparsec sembra migliore come testo-parser però. Si dovrebbe prendere in considerazione l'opzione.
  • Un'altra opzione è quella di utilizzare iteratee base-IO nel lungo periodo. John Lato ha fatto un ottimo articolo sulla iteratees nell'ultima lettore di Monade (numero # 16 credo). La condizione di fine linea è l'iteratees a segnale. Attenzione però che i tipi iteratee sono abbastanza scoraggiante e prendere un po 'di tempo per abituarsi.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top