J. *_*son 27
组合器try和lookAhead它们的相似之处在于它们都让Parsec"倒带",但它们适用于不同的情况.特别是,try倒带失败,同时lookAhead倒带成功.
通过文档,try"假装它在发生错误时没有消耗任何输入",而"在不消耗任何输入的情况下lookAhead p解析p",但"如果p失败并消耗一些输入,那么lookAhead".
因此,如果您认为解析器在某个流状态下运行并且失败或成功,我们可能会将其写为Haskell术语
type Parser a = [Tokens] -> (Either Error a, [Tokens])
Run Code Online (Sandbox Code Playgroud)
然后try确保如果(try p) input ---> (Left err, output)然后input == output和lookAhead具有它使得(lookAhead p) input ---> (Right a, output)然后input == output,但如果(lookAhead p) input ---> (Left err, output)那么它们可被允许不同.
我们可以通过直接查看Parsec的代码来看到这一点,这比我Parser上面的概念要复杂一些.首先我们来看看ParsecT
newtype ParsecT s u m a
= ParsecT {unParser :: forall b .
State s u
-> (a -> State s u -> ParseError -> m b) -- consumed ok
-> (ParseError -> m b) -- consumed err
-> (a -> State s u -> ParseError -> m b) -- empty ok
-> (ParseError -> m b) -- empty err
-> m b
}
Run Code Online (Sandbox Code Playgroud)
ParsecT是一种基于continuation的数据类型.如果你看看其中一个是如何构建的
ParsecT $ \s cok cerr eok eerr -> ...
Run Code Online (Sandbox Code Playgroud)
你会看到我们如何可以访问State s u,s,它决定和四个功能我们如何向前推进.例如,fail根据条款ParsecT的Monad实例使用eerr选项,构建ParseError来自当前输入位置与传递错误消息.
parserFail :: String -> ParsecT s u m a
parserFail msg
= ParsecT $ \s _ _ _ eerr ->
eerr $ newErrorMessage (Message msg) (statePos s)
Run Code Online (Sandbox Code Playgroud)
虽然最原始的成功令牌parse(tokenPrim)使用复杂的事件序列,最终最终以cok更新的方式调用State s u.
凭借这种直觉,其来源try特别简单.
try :: ParsecT s u m a -> ParsecT s u m a
try p =
ParsecT $ \s cok _ eok eerr ->
unParser p s cok eerr eok eerr
Run Code Online (Sandbox Code Playgroud)
它只是ParsecT根据传递给try的那个构建一个新的,但是"empty err"继续代替消耗的错误.无论下一次看到的解析组合器try p将无法访问其实际的"consumed err"连续性,因此保护尝试不会因错误而改变其状态.
但是lookAhead更复杂
lookAhead :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m a
lookAhead p = do{ state <- getParserState
; x <- p'
; setParserState state
; return x
}
where
p' = ParsecT $ \s cok cerr eok eerr ->
unParser p s eok cerr eok eerr
Run Code Online (Sandbox Code Playgroud)
只检查where-clause,我们看到它取决于修改传递的解析器p以使用"empty ok"continuation代替"consumed ok"continuation.这与try所做的是对称的.此外,它确保解析器状态不受p'通过其do-block 运行此修改时发生的任何事件的影响.