这是一个非常基本的问题,说实话,我觉得有点傻。
TL; DR:如何编写一个函数,利用parsec
库来模仿words
Data.List
函数的行为?预期行为的一个例子:
wordsReplica "I love lamp" = ["I","love","lamp"]
我刚刚从Real World Haskell
阅读了Parsec章节的前几页,了解什么构成了一个极小的解析函数(一个不仅仅返回参数或不返回任何内容)将会非常有用。 (RWH的介绍性示例显示了如何解析多行CSV文件...)
因此,我认为使用words
重写parsec
是一项有用的基本练习......结果证明不是那么基本(对我来说)......
以下是我的尝试;不幸的是,无论我给它什么,它都会产生“意外的输入结束”错误(在运行时)。我已经尝试在haskell.org上的parsec
库中阅读简单函数的描述/定义,但它们并不是那种说明性的,至少对于之前从未进行过任何解析的人来说,包括其他语言。
testParser :: String -> Either ParseError [[String]]
testParser input = parse dcParser "(unknown)" input
where
wordsReplica = endBy
(sepBy
(many (noneOf " "))
(char ' '))
(char ' ')
(请原谅lisp-y,非无点免费演示 - 当我学习新函数时,如果我使符号/结构超级明确,它会对我有所帮助。)
更新
这是朝着正确方向迈出的一步(但仍然没有,因为它没有做数字):
λ: let wordsReplica = sepBy (many letter) (char ' ')
λ: parse wordsReplica "i love lamp 867 5309"
Right ["i","love","lamp",""]
更新2:
似乎这个功能可以完成工作,但不确定它是多么惯用:
λ: let wordsReplica = sepBy (many (satisfy(not . isSpace))) (char ' ')
wordsReplica :: Stream s m Char => ParsecT s u m [[Char]]
λ: parse wordsReplica "" "867 5309 i love lamp %all% !(nonblanks are $$captured$$"
Right ["867","5309","i","love","lamp","%all%","!(nonblanks","are","$$captured$$"]
it :: Either ParseError [[Char]]
答案 0 :(得分:2)
更新2:
似乎这个功能完成了工作,但不确定它是多么惯用。
没关系,但它并不像你想要的那样有效:
> words "Hello world" ["Hello","world"] > parse wordsReplica "" "Hello world" Right ["Hello","","","","","","world"]
不完全是你想要的。毕竟,一个单词应至少包含一个字符。但是,如果您将many
更改为many1
,您会发现另一个错误:
> parse wordsReplicaMany1 "" "Hello world" Left (line 1, column 7): unexpected " "
那是因为你的分离解析器不够贪心。而不是解析单个空间,解析as many as you can:
nonSpace = satisfy $ not . isSpace
wordsReplica' = many1 nonSpace `sepBy` spaces