【问题标题】:Learning Haskell `parsec`: trying to rewrite `words` function as a basic exercise学习 Haskell `parsec`:尝试重写 `words` 函数作为基本练习
【发布时间】:2014-11-18 05:41:20
【问题描述】:

这是一个非常基本的问题,老实说,我觉得写它有点傻。

TL;DR: 我如何编写一个函数来利用 parsec 库来模仿来自 Data.Listwords 函数的行为?预期行为示例:

wordsReplica "I love lamp" = ["I","love","lamp"]

我刚刚阅读了 Real World Haskell 的 Parsec 章节的前几页,这将非常有助于理解什么是最低限度的解析函数(一个不仅仅返回参数或不返回任何内容的函数)。 (RWH 的介绍性示例展示了如何解析多行 CSV 文件...)

因此,我认为使用 parsec 重写 words 会是一个有用的基本练习...结果证明它不是那么基本(对我来说)...

以下是我的尝试;不幸的是,无论我给它什么,它都会产生一个“输入意外结束”错误(在运行时)。我已经尝试阅读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]]

【问题讨论】:

  • 出现问题的第一个提示是words 返回[String],但您的函数返回[[String]]。它总是抛出错误的原因是endBy x (char ' ') 接受最后一个字符为''的字符串,但内部解析器总​​是使用出现在字符串末尾的''字符。修复方法是删除endBy .. (char ' ') 部分并修复类型。
  • 干得好。请注意,words 不是解析器,而是拆分函数。最好通过指定允许的内容而不是允许任何不是分隔符的内容来进行解析。如果有任何问题,则说明您没有进行解析,因此您的下一个练习应该是关于允许和不允许什么的规则。

标签: haskell parsec


【解决方案1】:

更新 2:

似乎这个函数完成了工作,虽然我不确定它是多么地道。

这很好,但它并没有按你的意愿工作:

> 单词“你好世界” [“你好世界”] > 解析单词副本“”“Hello world” 对 ["Hello","","","","","","world"]

不是你想要的。毕竟,一个词至少应该包含一个字符。但是如果你把many改成many1,你会发现另一个错误:

> 解析 wordsReplicaMany1 "" "Hello world" 左(第 1 行,第 7 列): 出乎意料的“”

那是因为你的分离解析器不够贪婪。解析as many as you can:

,而不是解析一个单个空间
nonSpace      = satisfy $ not . isSpace
wordsReplica' = many1 nonSpace `sepBy` spaces

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-01
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多