为什么 ParsecT 类型有 'u' 参数?
Why does ParsecT type have 'u' argument?
parsec 包的文档states that u
参数用于通过单子计算携带一些用户状态。但是通过将 ParsecT
monad transformer 基于 State
monad 可以实现相同的功能。因此,如果我的解析器不是有状态的,我完全不需要 u
,但必须使用 parsec 将其设置为 ()
。向 ParsecT
添加非可选状态支持的理由是什么?
ParsecT
已经携带它自己的状态:解析位置和输入:http://haddocks.fpcomplete.com/fp/7.8/20140916-162/parsec/Text-Parsec-Prim.html#t:State
正如 指出的那样,这可能是出于优化目的。
因为 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 transformer的用户状态只保留成功的那个。
parsec 包的文档states that u
参数用于通过单子计算携带一些用户状态。但是通过将 ParsecT
monad transformer 基于 State
monad 可以实现相同的功能。因此,如果我的解析器不是有状态的,我完全不需要 u
,但必须使用 parsec 将其设置为 ()
。向 ParsecT
添加非可选状态支持的理由是什么?
ParsecT
已经携带它自己的状态:解析位置和输入:http://haddocks.fpcomplete.com/fp/7.8/20140916-162/parsec/Text-Parsec-Prim.html#t:State
正如
因为 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 transformer的用户状态只保留成功的那个。