Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell:在打结的同时处理循环依赖关系_Haskell_Type Inference_Cyclic Dependency_Tying The Knot_St Monad - Fatal编程技术网

Haskell:在打结的同时处理循环依赖关系

Haskell:在打结的同时处理循环依赖关系,haskell,type-inference,cyclic-dependency,tying-the-knot,st-monad,Haskell,Type Inference,Cyclic Dependency,Tying The Knot,St Monad,在编写具有本地类型推断功能的编程语言时(即,它能够推断除函数参数(如Scala)之外的类型),我遇到了循环依赖的问题 我通过递归地探索AST来执行类型检查/推断,并将每个可选类型的节点惰性地映射到一个类型检查节点。由于任何节点的类型都可能取决于AST中其他节点的类型,因此,我在这里打了个结,以便在推断/检查当前节点的类型时可以引用其他节点的类型(我将类型化的AST保留在读卡器monad的环境中) 这在典型情况下工作得很好,但由于循环依赖关系而崩溃,因为程序无休止地跟随循环以搜索已知类型 这类问题

在编写具有本地类型推断功能的编程语言时(即,它能够推断除函数参数(如Scala)之外的类型),我遇到了循环依赖的问题

我通过递归地探索AST来执行类型检查/推断,并将每个可选类型的节点惰性地映射到一个类型检查节点。由于任何节点的类型都可能取决于AST中其他节点的类型,因此,我在这里打了个结,以便在推断/检查当前节点的类型时可以引用其他节点的类型(我将类型化的AST保留在读卡器monad的环境中)

这在典型情况下工作得很好,但由于循环依赖关系而崩溃,因为程序无休止地跟随循环以搜索已知类型

这类问题的解决方案通常(据我所知)是维护一个已探索节点的集合,但我想不出一种在打结时进行此操作的引用透明方式,因为我事先不知道访问/评估节点的顺序,因为这取决于它们之间的依赖关系图

因此,我似乎需要维护一个本地的、可变的节点集合。为此,我尝试了以下方法:

  • 使用状态monad失败,因为每个子计算似乎都接收到自己的状态副本,因此无法在计算的不同分支之间共享有关已探索节点的信息
  • 将IO monad与IORefs一起使用,由于其严格性,这使我无法打结
  • 在IORefs中使用
    unsafePerformIO
    ,这会导致突变无序或根本不发生的问题
  • 将ST单子与STRefs一起使用,这在严格性方面引入了与IO单子相同的问题
最后,我提出了一个使用ST monad的解决方案,其中我使用
unsafeInterleaveST
在AST上进行映射时强制执行惰性求值,这很有效,但感觉很脆弱


是否有一个更惯用和/或更具参考价值的解决方案,而不是冗长或复杂?我本来会包括一个代码示例,但我对这个问题的最简单表述是大约250行。

我不知道有任何实际的类型检查器使用打结。我认为这不会让你走得很远。约束/元变量的状态是通常的实现,或简单情况下的双向类型检查。@András-Kovács我以前从未编写过编译器,但打结实现在我看来是一个合适的解决方案,因为它可以工作。我很想了解你提到的其他方法,谢谢你的发帖!扩展“约束”解决方案:当遇到相互递归块时,例如
let x=y;y=x in.
,您可以为所有变量指定一个新类型<代码>x:t0;y:t1并按顺序检查每个绑定。当推断
x=y
的类型时,您会发出一个等式约束
t0~t1
,并继续(不递归推断
y
的类型,因为它是同一相互块的一部分);然后,通过发出约束
t1~t0
,以相同的方式推断
y=x
。最后,您必须解决(琐碎的)统一问题
t0~t1/\t1~t0
;一种解决方案是
t0->t0;t1->t0
。就打结实现而言,我刚刚发现了
Control.Monad.ST.Lazy
,它省去了
unsafeInterleaveST
的需要,工作起来很有魅力:)我不知道有任何实际的类型检查器使用打结。我认为这不会让你走得很远。约束/元变量的状态是通常的实现,或简单情况下的双向类型检查。@András-Kovács我以前从未编写过编译器,但打结实现在我看来是一个合适的解决方案,因为它可以工作。我很想了解你提到的其他方法,谢谢你的发帖!扩展“约束”解决方案:当遇到相互递归块时,例如
let x=y;y=x in.
,您可以为所有变量指定一个新类型<代码>x:t0;y:t1并按顺序检查每个绑定。当推断
x=y
的类型时,您会发出一个等式约束
t0~t1
,并继续(不递归推断
y
的类型,因为它是同一相互块的一部分);然后,通过发出约束
t1~t0
,以相同的方式推断
y=x
。最后,您必须解决(琐碎的)统一问题
t0~t1/\t1~t0
;一种解决方案是
t0->t0;t1->t0
。就打结实现而言,我刚刚发现了
Control.Monad.ST.Lazy
,它省去了
unsafeInterleaveST
的需要,并且工作起来很有魅力:)