Я не могу нигде хранить глобальные данные с Haskell
Это не правда; в большинстве случаев достаточно что-то вроде State monad , но есть и монада ST .
Однако для этой задачи вам не нужно глобальное состояние. Написание парсера состоит из двух частей; лексический анализ и синтаксический анализ. Лексический анализ просто превращает поток символов в поток значимых токенов. Синтаксический анализ превращает токены в AST; Здесь вы должны разобраться с отступом.
Когда вы интерпретируете отступ, вы будете вызывать функцию-обработчик при изменении уровня отступа - когда он увеличивается (вложение), вы вызываете свою функцию-обработчик (возможно, с одним увеличенным аргументом, если вы хотите отслеживать уровень отступа) ); когда уровень снижается, вы просто возвращаете соответствующую часть AST из функции.
(Кроме того, использование глобальной переменной для этого - это то, что мне не пришло бы в голову и в императивном языке - во всяком случае, это переменная экземпляра. Монада State очень похожа концептуально на это.)
Наконец, я думаю, что фраза «я не могу поместить все свои правила лексизма в какую-либо монаду» указывает на какое-то недопонимание монад. Если бы мне нужно было проанализировать и сохранить глобальное состояние, мой код выглядел бы так:
data AST = ...
type Step = State Int AST
parseFunction :: Stream -> Step
parseFunction s = do
level <- get
...
if anotherFunction then put (level + 1) >> parseFunction ...
else parseWhatever
...
return node
parse :: Stream -> Step
parse s = do
if looksLikeFunction then parseFunction ...
main = runState parse 0 -- initial nesting of 0
Вместо комбинирования функциональных приложений с (.)
или ($)
вы объединяете их с (>>=)
или (>>)
. Кроме этого, алгоритм тот же. («Монада» не должна быть «внутри».)
Наконец, вам могут понравиться аппликативные функторы:
eval :: Environment -> Node -> Evaluated
eval e (Constant x) = Evaluated x
eval e (Variable x) = Evaluated (lookup e x)
eval e (Function f x y) = (f <$> (`eval` x) <*> (`eval` y)) e
(или
eval e (Function f x y) = ((`eval` f) <*> (`eval` x) <*> (`eval` y)) e
если у вас есть что-то вроде "funcall" ... но я отвлекся.)
Существует много литературы по разбору аппликативных функторов, монад и стрел; все из которых могут решить вашу проблему. Читайте о них и посмотрите, что вы получите.