Haskell 在标准下结合Alex和Happy”;单子;包装纸
我成功地结合了Alex lexer和Happy解析器。然而,我的工作中有一些方面我不满意:Haskell 在标准下结合Alex和Happy”;单子;包装纸,haskell,happy,alex,Haskell,Happy,Alex,我成功地结合了Alex lexer和Happy解析器。然而,我的工作中有一些方面我不满意: 建立初始状态 将状态传递给Alex时的样板代码 Alex和myExpParsermonad是分离的实体 我将在下面解释这些方面 我的ExpParsermonad如下所示: data ParserEnv = ParserEnv { varModifier :: String -> String } newtype ExpParser a = ExpParser { runExpParse
Alex
和myExpParser
monad是分离的实体ExpParser
monad如下所示:
data ParserEnv = ParserEnv
{ varModifier :: String -> String }
newtype ExpParser a = ExpParser
{ runExpParser :: ReaderT ParserEnv (StateT AlexState (Except String)) a }
deriving ( Functor, Applicative, Monad
, MonadReader ParserEnv
, MonadState AlexState
, MonadError String
)
顶级解析函数定义为:
-- | Parsing function.
parse :: (String -> String) -> String -> Either String Exp
parse f str = runExcept $ (`evalStateT` initState) $ runReaderT (runExpParser calc) initEnv
where initEnv = ParserEnv { varModifier = f}
initState = AlexState -- TODO: isn't it a standard initial state that we can use?
{ alex_pos = AlexPn 0 0 0
, alex_inp = str
, alex_chr = '\n' -- TODO: What to include here?
, alex_bytes = []
, alex_scd = 0
}
第一个问题是,我必须用一些我不确定的字段设置初始状态。此外,我希望为Alex lexer定义一个标准的“初始状态”
然后,我以以下方式使用lexer(使用“monad”包装器生成):
mLexer :: (Token -> ExpParser a) -> ExpParser a
mLexer cont = do -- TODO: is there a way to reduce this boilerplate?
alexSt <- get
case unAlex alexMonadScan alexSt of
Left err -> throwError err
Right (nextAlexSt, token) ->
do
put nextAlexSt
cont token
mLexer::(令牌->ExpParser a)->ExpParser a
mLexer cont=do--TODO:有没有办法减少这个样板文件?
阿列克斯特投手失误
右(nextAlexSt,令牌)->
做
下一步
连续令牌
但我正在编写一些样板文件,也在重复我自己,因为上面的代码中嵌入了状态monad的行为。如果Alex
为State
monad定义了一个实例,我可以避免这种情况,但我认为情况并非如此
在上述方面是否有改进当前解决方案的方法?“Alex和Axel”?你是说“Alex和Happy”?是的。谢谢。为什么不用
ExpParser
作为Alex的单子呢?