我不能在任何地方存储任何全局数据哈斯克尔
这是不正确的;在大多数情况下,像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