Как использовать комбинаторы мегапарсек на StateT

Я строю компилятор для Java для университетского проекта, в моем проекте мои парсеры в основном StateT (Scope,SymbolTable) String m a где Scope это область, в которой мы находимся сейчас (метод, класс и т. д.) и SymbolTable содержит символы, определенные до сих пор.

Я хотел использовать комбинаторы мегапарсек на этих парсерах, для parens,braces это не проблема, я просто использую 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 снова и снова и...

Как использовать такие комбинаторы мегапарсек, как sepBy,sepEndBy и т. д., чтобы я много раз запускал парсер, но связывал результирующее состояние с первого на второе и третье и т. д.?

2 ответа

Решение

Я не знаю, почему я думал, что мне нужна специальная функция, чтобы сделать это, sepBy и другие определены на Alternative и потому что каждый StateT имеет Alternative функции экземпляра, такие как sepBy,manyи т. д. можно вызвать напрямую.

Моя проблема, вероятно, заключалась в том, что я должен был использовать symbol,charи т.д., которые я думал ParsecT ... но потом я понял, что эти функции определены с точки зрения MonadParsec класс типов, который StateT снова есть экземпляр, так что мне даже не нужно lift или же mapStateT,

Так что все, что я сделал, это изменил сигнатуры функций для работы с MonadParsec и моя проблема была решена.

Мегапарсек имеет монадный трансформаторный интерфейс ParsecT:

data ParsecT e s m a

ParsecT e s m a парсер с пользовательским компонентом данных об ошибках e тип потока s лежащая в основе монада m и тип возврата a,

Вы должны быть в состоянии использовать это с чем-то вроде type Parser = ParsecT Dec Text (State (Scope, SymbolTable)), который добавит функциональность синтаксического анализа в базовый State (Scope, SymbolTable) монада.

Другие вопросы по тегам