为什么ParsecT类型有'你'的说法?

arr*_*owd 8 haskell parsec state-monad monad-transformers

parsec包的文档声明该 u参数用于通过monadic计算来携带一些用户状态.但是通过ParsecTStatemonad 上建立monad 变换器可以实现相同的功能.因此,如果我的解析器不是有状态的,我不需要u完全,但必须将其设置为()parsec.添加非可选状态支持的理由是什么ParsecT

Lam*_*eek 5

因为类型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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,底层状态monad注册了两个tick(来自两个尝试的替代方案),而Parsec monad转换器的用户状态只保留了成功的一个.