在编写将使用本地类型推断的编程语言时(即它能够推断除函数参数之外的类型,如Scala),我遇到了循环依赖的问题。
我通过递归地探索AST来执行类型检查/推理,并且懒洋洋地将每个可选类型的节点映射到经过类型检查的节点。因为任何节点的类型可能取决于AST中其他节点的类型,所以我打结了结,这样我就可以在推断/检查当前节点的类型时引用其他节点的类型(我保留读取器monad环境中的typed-AST。
这在典型的情况下运行得非常好,但是因为程序在搜索已知类型时无休止地跟随循环,因此会出现循环依赖性。
这种问题的解决方案一般(据我所知)是维护一组被探索的节点,但是我不能想到在结对的时候采用引用透明的方式,因为我不知道提前访问/评估节点的顺序,因为这取决于它们彼此之间的依赖关系图。
因此,似乎我需要维护一个本地的,可变的探索节点集合。为此,我尝试了以下方法:
unsafePerformIO
与IORefs一起使用,这会引起无序或根本不发生突变的问题。最后,我想出了一个使用ST monad的解决方案,在使用unsafeInterleaveST
进行AST映射的同时强制进行延迟评估,这有效,但感觉很脆弱。
是否存在更加惯用和/或引用透明的解决方案,这种解决方案并非冗长或复杂?我会包含一个代码示例,但我对此问题的最简单的表述是~250行。