Сочетание Алекса и Хеппи под стандартной "монадной" оберткой
Мне удалось совместить Алекс лексер и Счастливый парсер. Однако есть некоторые аспекты моего текущего решения, которыми я не доволен:
- Настройка начального состояния,
- Код Boilerplate при передаче состояния Алексу,
Alex
и мойExpParser
Монада это отдельные сущности.
Я объясню эти аспекты ниже.
мой ExpParser
Монада выглядит следующим образом:
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.
Затем я использую лексер (сгенерированный с использованием оболочки "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
Но я пишу некоторые шаблоны, а также повторяю себя, поскольку в приведенном выше коде есть поведение монады состояния. Если Alex
определил экземпляр для State
Монада Я мог бы избежать этого, однако я не думаю, что это так.
Есть ли способы улучшить текущее решение в аспектах, упомянутых выше?