Haskell编译器如何在没有完全重新编译的情况下处理大型项目的小更改?

Haskell编译器如何在没有完全重新编译的情况下处理大型项目的小更改?,haskell,Haskell,我是哈斯凯尔n00b,我想了解更多。我想知道Haskell是一种惰性评估语言,它可能需要分析函数调用的所有可能流。鉴于此,如果任何函数调用的可传递依赖项发生变化,那么它不需要重新编译该函数吗?如果有这么小的更改,可能会层叠而来,需要完全重新编译。这是如何处理的?(我以CW的身份回答这个问题,因为我不是专家,我希望能找到正确的答案。) 有很多信息 您关于“分析函数调用的所有可能流”的说明有点偏离目标——最好将大部分评估视为发生在运行时系统中,而不是编译时。更大的担忧是,大多数重要的程序完全依赖于G

我是哈斯凯尔n00b,我想了解更多。我想知道Haskell是一种惰性评估语言,它可能需要分析函数调用的所有可能流。鉴于此,如果任何函数调用的可传递依赖项发生变化,那么它不需要重新编译该函数吗?如果有这么小的更改,可能会层叠而来,需要完全重新编译。这是如何处理的?

(我以CW的身份回答这个问题,因为我不是专家,我希望能找到正确的答案。)

有很多信息

您关于“分析函数调用的所有可能流”的说明有点偏离目标——最好将大部分评估视为发生在运行时系统中,而不是编译时。更大的担忧是,大多数重要的程序完全依赖于GHC的积极优化,特别是普及的内联。使用内联意味着在重新编译值时重新编译所有调用站点


出于类似的原因,我认为GHC在“编译单元”方面比其他语言保守得多。特别是,值的类型签名不会像在其他语言的调度或链接系统中那样封装其接口。例如,GHC“导出函数的严格性、算术性和展开性。这对于跨模块优化至关重要;但只有在使用-O编译时才包括它。”(有关算术性的一点信息,请参见此处的链接。)这些特性都不是函数类型的一部分,但是对于如何编译下游模块有重要影响。

如果修改了函数,则需要重新编译。任何依赖于该函数或模块的内容都需要重新编译。这不是Haskell特有的,而是大多数现代编译器的工作方式。如果我在编写C、Java、C#或其他任何东西,更改一个函数可以级联成一个大型的重新编译,但是构建系统可以自动确定需要重新编译的内容(请参阅:make,shake)。C、Java和C#都有编译单元。如果函数发生了更改且其签名没有更改,则只需要重新编译单个文件(编译单元)。如果函数签名更改,则只需要重新编译直接依赖项,而不需要重新编译传递依赖项。至少在GHC中,如果函数很小,编译器可以选择将其内联,即使在当前文件之外的调用中也是如此。这是通过将其代码及其类型签名复制到interface.hi文件中来完成的。这样做的代价是,如果导出的接口发生更改,即如果代码或类型发生更改,则需要重新编译直接依赖项。如果由于这个原因,依赖项现在有了不同的接口(例如嵌套内联),那么重新编译将进一步扩展。ghc——制造和阴谋集团根据需要正确递归。这怎么会“太宽泛”?这是完全可以回答的。@alternative-“可能有太多的答案,或者好的答案对于这种格式来说太长了。”我不确定我是否理解“尤其是,值的类型签名没有像在其他语言的调度或链接系统中那样封装其接口。”。你能解释一下你所说的接口封装的区别吗?