我不能在任何地方存儲任何全局數據哈斯克爾
這是不正確的;在大多數情況下,像State monad就足夠了,但也有ST monad。
但是,您不需要全局狀態來執行此任務。編寫解析器由兩部分組成;詞法分析和語法分析。詞法分析只是將一串字符變成一串有意義的記號。語法分析將令牌轉化爲AST;這是你應該處理縮進的地方。
在解釋縮進時,隨着縮進級別的改變,你會調用一個處理函數 - 當它增加(嵌套)時,你調用你的處理函數(也許增加一個arg,如果你想跟蹤縮進水平);當級別降低時,您只需從函數返回相關的AST部分。
(順便說一下,使用全局變量對於我來說不會出現在命令式語言中 - 如果有的話,它是一個實例變量,State monad在概念上與此非常相似。)
最後,我認爲「我不能把我所有的規則放在任何monad中」這句話表示對monad的某種誤解。如果我需要分析和保持全局狀態,我的代碼看起來像:
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」 ...但我離題了。)
有大量關於應用函子,monads和箭頭解析的文獻;所有這些都有可能解決您的問題。閱讀這些內容,看看你得到了什麼。
不錯。我最終和Alex玩了一下,發現它在某些方面比PArrows更清潔(這通常是我所能達到的)。感謝您的信息:) – jrockway
啊,謝謝你。我也問過#haskell,發現了用於alex的UserState包裝器。雖然沒有太多的文件,但必須做一些源搜索。 我知道國家單體,但我不確定穿過亞歷克斯的詞法分析器穿線狀態。 感謝您的幫助。 – kamatsu