Parsing 如何实现parsec';试一试?

Parsing 如何实现parsec';试一试?,parsing,haskell,monads,Parsing,Haskell,Monads,我想实现与parsec方法相同的方法。但我使用的不是解析转换器,而是保存状态的解析器对象: try :: Parser String -> Parser String try p = P $ \s -> case doParse p s of [] -> [("", s)] [(a, s')] -> [(a, s')] 我敢肯定我的努力是远远不够的。因此,任何帮助都将不胜感激 newtype Parser a = P (S

我想实现与parsec方法相同的方法。但我使用的不是解析转换器,而是保存状态的
解析器
对象:

try :: Parser String -> Parser String
try p = P $ \s -> case doParse p s of
            [] -> [("", s)]
            [(a, s')] -> [(a, s')]
我敢肯定我的努力是远远不够的。因此,任何帮助都将不胜感激

newtype Parser a = P (String -> [(a, String)])

instance Functor Parser where
   fmap = liftA

instance Applicative Parser where
   pure x    = P (\cs -> [ (x,cs) ])
   p1 <*> p2 = P (\cs -> do (f, cs')  <- doParse p1 cs
                            (x, cs'') <- doParse p2 cs'
                            return (f x, cs''))

instance Monad Parser where
    return = pure
    p1 >>= f = P (\cs -> let [(a, s)] = doParse p1 cs
                         in doParse (f a) s)

instance Alternative Parser where
  -- the parser that always fails
  empty     = P $ const []
  -- | Combine two parsers together in parallel, but only use the
  -- first result. This means that the second parser is used only
  -- if the first parser completely fails.
  p1 <|> p2 = P $ \cs -> case doParse (p1 `choose` p2) cs of
                          []   -> []
                          x:_ -> [x]

doParse :: Parser a -> String -> [(a, String)]
doParse (P p) = p
simpleComment与manyTill一起取自Parsec网站:

simpleComment   = do{ string "<!--"
                     ; manyTill anyChar (try (string "-->"))
                     }

manyTill p end      = scan
                    where
                      scan  = do{ _ <- end; return [] }
                            <|>
                              do{ x <- p; xs <- scan; return (x:xs) }
simpleComment=do{string”“)
}
manyTill p end=扫描
哪里

scan=do{{up>您不需要为您的解析器类型使用
try
。或者,如果您确实需要,您可以简单地将其定义为:

try :: Parser a -> Parser a
try = id
Parsec区分了在使用某些输入后失败和在不使用任何输入的情况下失败。例如,如果您查看Parsec的文档,您会发现一段重要的强调文本:

解析器
pq
首先应用
p
。如果成功,则返回
p
的值。如果
p
失败而不消耗任何输入,则尝试解析器
q

未说明的事实是,如果
p
在消耗部分输入后失败,则整个过程将失败,并且
q
从未尝试过。这意味着在Parsec中,解析器:

broken :: Parser String
broken = string "hello" <|> string "hi"
要解决此问题,您必须使用
try
,它允许您覆盖此规则:

okay :: Parser String
okay = try (string "hello") <|> string "hi"
您的解析器是不同的。尽管您没有给出
choose
的定义,但我可以从您的
解析器类型中看出,它没有合理的方式来表示“使用输入后失败”与“不使用输入时失败”因此,当
p
失败时,您的
pq
实现无疑会尝试
q
,即使它在处理一点输入后失败


因此,您的解析器的行为就像每个术语都被
try
包围一样,因此
try
函数将是多余的。

您不需要
try
作为您的解析器。或者,如果您真的想要一个,您可以简单地将其定义为:

try :: Parser a -> Parser a
try = id
Parsec区分了在使用某些输入后失败和在不使用任何输入的情况下失败。例如,如果您查看Parsec的文档,您会发现一段重要的强调文本:

解析器
pq
首先应用
p
。如果成功,则返回
p
的值。如果
p
失败而不消耗任何输入,则尝试解析器
q

未说明的事实是,如果
p
在消耗部分输入后失败,则整个过程将失败,并且
q
从未尝试过。这意味着在Parsec中,解析器:

broken :: Parser String
broken = string "hello" <|> string "hi"
要解决此问题,您必须使用
try
,它允许您覆盖此规则:

okay :: Parser String
okay = try (string "hello") <|> string "hi"
您的解析器是不同的。尽管您没有给出
choose
的定义,但我可以从您的
解析器类型中看出,它没有合理的方式来表示“使用输入后失败”与“不使用输入时失败”因此,当
p
失败时,您的
pq
实现无疑会尝试
q
,即使它在处理一点输入后失败


因此,您的解析器的行为就像每个术语都被
try
包围一样,因此
try
函数是多余的。

为什么您认为您需要一个与
try
等价的函数?我正在解析HTML,并且需要它来实现前瞻功能您的
(>=)
方法看起来可疑。如果
doParse p1 cs
返回多个结果,或者不返回,该怎么办?是的,目前它只返回第一个结果..我将从这里的测试开始。首先显示(你自己)您需要解析的内容以及当前组合符的不足之处。请保持简单。为什么您认为您需要一个等价的
try
?我正在解析HTML并需要它来实现前瞻功能您的
(>>=)
方法看起来可疑。如果
doParse p1 cs
返回多个结果,或者不返回,该怎么办?是的,目前它只返回第一个结果。我将从这里的测试开始。首先显示(你自己)你需要解析什么,以及你当前的组合如何不足。保持简单。
> parseTest okay "hello"
"hello"
> parseTest okay "hi"
"hi"