【发布时间】:2021-04-18 17:37:47
【问题描述】:
我正在阅读这篇 Monadic Parsing 文章,当时我正在尝试在 Haskell 中实现一个非常简单的字符串解析器,并更好地了解如何使用 monad。在下面你可以看到我的代码,实现了匹配单个字符或整个字符串的函数。它按预期工作,但我观察到两种我无法解释的奇怪行为。
-
我必须处理
string中的单个字符,否则解析器将只返回空列表。确切地说,如果我删除此行string [c] = do char c; return [c],它将不再起作用。我期待string (c:s)能正确处理string (c:[])。这可能是什么原因? -
在我看来,
string定义应该等同于string s = mapM char s,因为它会为s中的每个字符创建一个[Parser Char]列表并将结果收集为Parser [Char]。如果我使用基于mapM的定义,程序将陷入无限循环并且不会打印任何内容。我在这里想念一些关于惰性评估的事情吗?
.
module Main where
newtype Parser a = Parser { apply :: String->[(a, String)] }
instance Monad Parser where
return a = Parser $ \s -> [(a, s)]
ma >>= k = Parser $ \s -> concat [apply (k a) s' | (a, s') <- apply ma s]
instance Applicative Parser where
pure = return
mf <*> ma = do { f <- mf; f <$> ma; }
instance Functor Parser where
fmap f ma = f <$> ma
empty :: Parser a
empty = Parser $ const []
anychar :: Parser Char
anychar = Parser f where
f [] = []
f (c:s) = [(c, s)]
satisfy :: (Char -> Bool) -> Parser Char
satisfy prop = do
c <- anychar
if prop c then return c
else empty
char :: Char -> Parser Char
char c = satisfy (== c)
string :: String -> Parser String
string [] = empty
string [c] = do char c; return [c] --- if I remove this line, all results will be []
string (c:s) = do char c; string s; return (c:s)
main = do
let s = "12345"
print $ apply (string "123") s
print $ apply (string "12") s
print $ apply (string "1") s
print $ apply (string []) s
PS。我认为问题的标题不够有启发性,如果您有更好的想法,请提出修改建议。
【问题讨论】:
-
关于不相关的说明:考虑为
Parser定义一个Alternative实例,而不是用相同的名称 (empty) 组成您自己的不相关事物。