gpt4 book ai didi

haskell - Parsec - 错误 "combinator ' many' 应用于接受空字符串的解析器“

转载 作者:行者123 更新时间:2023-12-04 10:20:47 26 4
gpt4 key购买 nike

我正在尝试使用 Parsec 编写一个解析器,它将解析读写的 Haskell 文件,如下所示:

The classic 'Hello, world' program.

\begin{code}

main = putStrLn "Hello, world"

\end{code}

More text.

我写了以下内容,有点受 RWH 中示例的启发:
import Text.ParserCombinators.Parsec

main
= do contents <- readFile "hello.lhs"
let results = parseLiterate contents
print results

data Element
= Text String
| Haskell String
deriving (Show)


parseLiterate :: String -> Either ParseError [Element]

parseLiterate input
= parse literateFile "(unknown)" input



literateFile
= many codeOrProse

codeOrProse
= code <|> prose

code
= do eol
string "\\begin{code}"
eol
content <- many anyChar
eol
string "\\end{code}"
eol
return $ Haskell content

prose
= do content <- many anyChar
return $ Text content

eol
= try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"

我希望这会产生以下结果:
[Text "The classic 'Hello, world' program.", Haskell "main = putStrLn \"Hello, world\"", Text "More text."]

(允许空格等)。

这编译得很好,但是在运行时,我得到了错误:
*** Exception: Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string

任何人都可以对此有所了解,并可能提供解决方案吗?

最佳答案

正如某物指出的 many anyChar是问题所在。但不只是在prose而且在code . code 的问题是,content <- many anyChar将消耗一切:换行符和 \end{code}标签。

所以,你需要有一些方法来区分散文和代码。一个简单(但可能太天真)的方法是寻找反斜杠:

literateFile = many codeOrProse <* eof

code = do string "\\begin{code}"
content <- many $ noneOf "\\"
string "\\end{code}"
return $ Haskell content

prose = do content <- many1 $ noneOf "\\"
return $ Text content

现在,您并没有完全得到想要的结果,因为 Haskell部分也将包含换行符,但您可以很容易地过滤掉它们(给定一个函数 filterNewlines 你可以说 `content <- filterNewlines <$> (many $ noneOf "\\") )。

编辑

好的,我想我找到了一个解决方案(需要最新的 Parsec 版本,因为 lookAhead ):
import Text.ParserCombinators.Parsec
import Control.Applicative hiding (many, (<|>))

main
= do contents <- readFile "hello.lhs"
let results = parseLiterate contents
print results

data Element
= Text String
| Haskell String
deriving (Show)

parseLiterate :: String -> Either ParseError [Element]

parseLiterate input
= parse literateFile "" input

literateFile
= many codeOrProse

codeOrProse = code <|> prose

code = do string "\\begin{code}\n"
c <- untilP (string "\\end{code}\n")
string "\\end{code}\n"
return $ Haskell c

prose = do t <- untilP $ (string "\\begin{code}\n") <|> (eof >> return "")
return $ Text t

untilP p = do s <- many $ noneOf "\n"
newline
s' <- try (lookAhead p >> return "") <|> untilP p
return $ s ++ s'
untilP p解析一行,然后检查下一行的开头是否可以通过 p成功解析.如果是,则返回空字符串,否则继续。 lookAhead是必需的,否则会消耗开始\结束标记和 code无法认出他们。

我想它仍然可以更简洁(即不必在 string "\\end{code}\n" 内重复 code )。

关于haskell - Parsec - 错误 "combinator ' many' 应用于接受空字符串的解析器“,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7753959/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com