我正在关注this tutorial在Haskell中实现Parser Combinators(la parsec)。我实现了这篇文章中提到的所有NanoParsec。
现在几个小时,我正在努力实施
-- try p. If p fails continue without consuming anything
try :: Parser a -> Parser a
try p = ...
-- Parser for everything, until the character-sequence stop appears.
-- If stop does not appear at all: fail
untilStop :: String -> Parser String
untilStop stop = ...
我实现untilStop
的最佳尝试看起来有点像这样并且不能正常工作
untilStop :: String -> Parser String
untilStop (c : cs) = do
s <- some $ satisfy (/= d)
string (c : cs) <|> do
i <- item
untilStop (d : ds)
-- maybe use msum from MonadPlus to combine?
我无法弄清楚如何将s
,i
和递归调用结合起来而不会因为string
未能将所有内容整合在一起而导致失败。
我认为,一旦我try
,untilStop
应该是直截了当的。有人可以指出我正确的方向或为我实施它(try
)吗?
现在我还在学习Monads,Applicative和相关的东西,所以试图理解parsec的源代码对我来说是不可能的。
答案 0 :(得分:1)
正如我在评论中所说,我认为你不需要像Parsec一样try
。
对于untilStop
,请检查:
untilStop :: String -> Parser String
untilStop [] = everything
untilStop (c:cs) = item >>= fun
where fun i = do { s <- untilStop cs;
if i == c && s == "" then return "" else failure } <|> do
s <- untilStop (c : cs)
return (i : s)
首先,如果停止字符串为空,则解析所有内容。 everything
的位置:
everything :: Parser String
everything = Parser (\inp -> [(inp,"")])
否则,如果它的格式为c:cs
,则解析一个字符i
并考虑两种情况:
停止字符串位于解析流的前面(因为c == i
并使用字符串cs
的其余部分解析得到一个空结果),然后返回“”。或者,
它位于流中的某个位置,因此您需要进一步查找。
请注意,<|>
运算符用于回溯。如果untilStop cs
无法满足我们的要求,我们需要使用untilStop (c:cs)
来重新分析。