parsec 软件包states that u参数的文档用于通过单子(monad)计算来承载某些用户状态。但是,可以通过将ParsecT monad转换器基于State monad来实现相同的功能。因此,如果我的解析器不是有状态的,则我完全不需要u,而必须使用parsec将其设置为()。向ParsecT添加非可选状态支持的基本原理是什么?

最佳答案

因为在回溯方面,ParsecT s () (State st) a类型的解析器的行为与Parsec s st Identity a类型的解析器的行为不同:

  • 当parsec在不消耗任何输入的解析失败后尝试替代方法时,将重置用户状态。
  • 但是底层的Monad m不会回溯;保留最终解析结果过程中发生的所有影响。

  • 考虑以下示例:
    {-# LANGUAGE FlexibleContexts #-}
    module Foo where
    
    import Control.Applicative
    import Control.Monad.State
    import Text.Parsec.Prim hiding ((<|>), State(..))
    import Text.Parsec.Error (ParseError)
    
    tick :: MonadState Int m => ParsecT s Int m ()
    tick = do
      lift $ modify (+1)
      modifyState (+1)
    
    tickTock :: MonadState Int m => ParsecT s Int m ()
    tickTock = (tick >> empty) <|> tick
    
    -- | run a parser that has both user state and an underlying state monad.
    --
    -- Example:
    -- >>> run tickTock
    -- (Right 1,2)
    run :: ParsecT String Int (State Int) () -> (Either ParseError Int, Int)
    run m = runState (runParserT (m >> getState) initUserState "-" "") initStateState
      where initUserState = 0
            initStateState = 0
    

    如您所见,基础状态monad记录了两个滴答声(来自尝试过的两个选择),
    而Parsec monad变压器的用户状态仅保留成功状态。

    关于haskell - 为什么ParsecT类型具有 'u'参数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27835214/

    10-11 08:07
    查看更多