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

时间:2015-01-08 07:44:55

标签: haskell parsec monad-transformers state-monad

parsec states that u参数的文档用于通过monadic计算来携带一些用户状态。但是ParsecT monad变换器基于State monad,可以实现相同的功能。因此,如果我的解析器不是有状态的,我不需要u,但必须使用parsec将其设置为()。向ParsecT添加非可选状态支持的理由是什么?

2 个答案:

答案 0 :(得分: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

正如你所看到的,潜在的状态monad注册了两个ticks(来自两个被尝试的替代品), 而Parsec monad变压器的用户状态只保留了成功状态。

答案 1 :(得分:1)

ParsecT已经拥有了自己的状态:解析位置和输入:http://haddocks.fpcomplete.com/fp/7.8/20140916-162/parsec/Text-Parsec-Prim.html#t:State

正如leftaroundabout指出的那样,它可能是出于优化目的。