詳細闡述@Daniel Wagner的答案......方式解析器通常使用Parsec構建,您可以從解析特定字符(例如,加號或數字)的低級解析器開始,然後在頂部構建解析器他們使用組合器(如many1
組合器,該組合器將讀取單個數字的解析器轉換爲讀取一個或多個數字的解析器,或解析器「一個或多個數字」,然後跟隨「加號」,接着是「一個或多個數字「)。
但是,每個解析器,無論是低級數字解析器還是更高級別的「添加表達式」解析器,都旨在直接應用於相同的輸入流。
你做什麼不通常要做的就是寫狼吞虎嚥的輸入流的數據塊產生,也就是說,一個String
和另一解析器解析解析器String
(而不是原來的輸入流)和嘗試將它們結合起來。這是Parsec不直接支持的那種「垂直組合」,看起來不自然和非單調。
正如在評論中指出,有一些情況下豎構圖是最乾淨的總體方法(當你有一個語言嵌入式組件或其他語言的表達式中一樣),但它沒有采取通常的做法由一個Parsec解析器。
應用程序的底線是cell
解析器只生成String
太專業化,無法使用。爲CSV文件更加有用秒差距的框架應該是:
import Text.Parsec
import Text.Parsec.String
-- | `csv cell` parses a CSV file each of whose elements is parsed by `cell`
csv :: Parser a -> Parser [[a]]
csv cell = many (row cell)
-- | `row cell` parses a newline-terminated row of comma separated
-- `cell`-expressions
row :: Parser a -> Parser [a]
row cell = sepBy cell (char ',') <* char '\n'
現在,您可以編寫解析正整數自定義單元格解析器:
customCell :: Parser Int
customCell = read <$> many1 digit
並解析CSV文件:
> parse (csv customCell) "" "1,2,3\n4,5,6\n"
Right [[1,2,3],[4,5,6]]
>
這裏,「細胞」是一個隱含的上下文,而不是將子分析器明確地將逗號分隔的單元格解析爲要提供給不同解析器的字符串,其中suppl ied cell parser被調用來在適當的位置解析底層輸入流,其中在輸入流中間的行中間會出現逗號分隔的單元格。
我不確定垂直分析器組成的含義。你介意擴大一點嗎? – gallais
@gallais我的意思是你要求的操作:一種採用「Parser Foo [Bar]」和「Parser Bar Baz」並將其變成「Parser Foo Baz」的方法。 –
哦,我明白了。用這些簡單的類型,我的目標比OP的問題更清晰。感謝您的澄清! – gallais