Я конвертирую контекстно-свободную грамматику в нормальную форму Грейбаха (GNF). Основное преобразование (от Hopcroft & Ullman) представляет собой последовательность итераций по индексированным переменным грамматики. По сути, это «безгражданство». Я реализовал это как последовательность сгибов по соответствующим индексам (реализация довольно проста):
gnf :: Ord a => Set (Rule a) -> Set (Rule a)
gnf rl = foldl step1 rl [1..maxIndex rl]
where step1 rl' k = foldl step2 rl' [1..k - 1]
where step2 rl'' j = noLR k (subst rl'' k j)
maxIndex rl возвращает максимальный индекс переменной в наборе правил; subst rl k j выполняет замену правил с индексом k правилами, правая часть которых начинается с переменной с индексом j. После выполнения gnf мне нужно выполнить последний проход по грамматике в обратном порядке.
Проблема заключается в noLR, который преобразует грамматику с леворекурсивными k-индексированными правилами. Это функция с отслеживанием состояния, поскольку для каждого правила (или k-индексированного правила), к которому применяется noLR, должна быть создана уникальная переменная. Итак, я написал функцию с отслеживанием состояния
noLR :: Ord a => Int -> Set (Rule a) -> State [Sym a] (Set (Rule a))
noLR rl = do (n:ns) <- get; put ns;
let rl' = ... remove left recursion rl n ...
in return rl'
Я могу упорядочить вместе noLR, чтобы обновить n, который noLR принимает в качестве параметра. Однако я не знаю, как выполнить noLR внутри шага 2 в приведенной выше функции. Кажется, я не могу использовать схему let... in, потому что вычисление с отслеживанием состояния встроено в несколько рекурсивных функций.
Я хочу, чтобы n была неким типом глобальной переменной, похожей на явную поточность n, которую я могу вызывать и обновлять внутри шага2, поэтому изначально я написал функцию как складку с эта-расширением (для n). Кто-нибудь знает, как я могу структурировать gnf внутри монады состояния для достижения такого эффекта? За исключением последнего вычисления в сгибе, ничто другое не является «с сохранением состояния», и мне удобно использовать монаду состояния только с «тривиальными» примерами. Я скорее потерян.
foldM
.gnf
, конечно, будет начинаться с вызова evalState верхнего уровня. - person sclv   schedule 23.11.2010