attoparsec建议我解析一个文件,现在我必须要了解如何使用它; 有人给了我这段代码:
type Environment = M.Map String String
import Data.Attoparsec (maybeResult)
import qualified Data.Attoparsec.Char8 as A
import qualified Data.ByteString.Char8 as B
environment :: A.Parser Environment
environment = M.fromList <$> A.sepBy entry A.endOfLine
parseEnvironment = maybeResult .flip A.feed B.empty . A.parse environment
spaces = A.many $ A.char ' '
entry = (,) <$> upTo ':' <*> upTo ';'
upTo delimiter = B.unpack <$> A.takeWhile (A.notInClass $ delimiter : " ")
<* (spaces >> A.char delimiter >> spaces)
效果很好,但我不知道为什么: 使用翻转的原因是什么,将A.feed的参数置于不同的顺序并不容易?为什么有B.empty? 有一些关于我可以学习的教程吗? 提前谢谢
答案 0 :(得分:4)
在this StackOverflow question的答案中,feed
需要pointfree
。正如Bryan O'Sullivan(Attoparsec的创始人)所说:
如果你写一个attoparsec解析器 消耗尽可能多的输入 在失败之前,你必须告诉 部分结果延续时 你已经到了输入的最后。
你可以通过输入一个空的字节串来实现这一点。
我承认我编写了有问题的代码,在这种情况下我实际上没有使用A.parse environment
。简单的构图对我来说很有意义:你运行解析器(flip A.feed B.empty
),你告诉它你完成了(Maybe
),然后转换为maybeResult
作为一种基本错误处理(parseEnvironment b = maybeResult $ A.feed (A.parse environment b) B.empty
)。在我看来,这比尖头版本更清晰:
>>
其余的是我认为相当惯用的applicative parsing,虽然我不确定为什么我会使用*>
代替{{1}}。