如何在 State 上使用 megaparsecs 组合器

how to use megaparsec's combinators on StateT

我正在为大学项目 java 构建编译器,在我的项目中,我的解析器主要是 StateT (Scope,SymbolTable) String m a,其中 Scope 是我们现在的范围(方法, class,etc) 和 SymbolTable 包含到目前为止定义的符号。

我想在那些解析器上使用 megaparsec 的组合器,对于 parensbraces 这不是问题,我只使用 mapStateT 但对于 sepBy 和我开发的其他人这个函数:

mapsequence :: (Monoid s,Monad m) => (m (a,(b,s)) -> m [(a,(b,s))]) -> StateT (b,s) m a -> StateT (b,s) m [a]
mapsequence f stm = do
                      s <- get
                      ases <- lift $ f $ runStateT stm s
                      case ases of
                        (_:_) -> do
                               put ((fst . snd . last) ases,(mconcat . map (snd . snd)) ases)
                               return $ map fst ases
                        [] -> return []

现在 f 例如:

\p -> p `sepBy` semi

无论如何我最近意识到上面的函数是错误的,该函数将 运行 解析器(封装在 StateT 中)提供我们现在的状态 s然后它将再次 运行 它但不是将第一个 运行 产生的新状态提供给它,而是一次又一次地提供它 s 和...。

如何使用 megaparsec 的组合器,如 sepBysepEndBy 等,以便我 运行 解析器多次但将结果状态从第一个链接到第二个到第三等 ?

Megaparsec 有一个 monad 转换器接口 ParsecT:

data ParsecT e s m a

ParsecT e s m a is a parser with custom data component of error e, stream type s, underlying monad m and return type a.

您应该能够将它与 type Parser = ParsecT Dec Text (State (Scope, SymbolTable)) 之类的东西一起使用,它将向底层 State (Scope, SymbolTable) monad 添加解析功能。

我不知道为什么我认为我需要一个特殊的函数来做到这一点,sepBy 和其他定义在 Alternative 上,因为每个 StateT 都有一个 Alternative实例函数如sepBymany等可以直接调用。

我的问题可能是因为我不得不使用 symbolchar 等,我认为它们是 ParsecT ... 但后来我意识到这些函数是根据 MonadParsec 类型类 StateT 再次具有实例,所以我什至不需要 liftmapStateT

所以我所做的就是更改函数签名以使用 MonadParsec,我的问题就解决了。