Haskell 有许多用于调试运行时性能问题的出色工具,但有哪些工具/经验法则可用于调试编译时性能问题?
具体来说,我的一些代码中的约束求解器需要永远(从 1-2 秒到几分钟)。我很确定这是由于我如何在约束中使用类型族,但我不知道在这种情况下什么样的东西是昂贵的,也不知道如何查看约束求解器在哪里花费时间。我最好的猜测是,我对类型列表的操作之一是采用二次时间而不是线性时间。
让我们看一个为什么我怀疑约束求解器的例子。在我的文件中,我的代码如下所示:
class ExampleClass a where
type ExampleType a
f :: ExampleType a -> a
data ExampleData (xs :: [a]) = ...
instance
( Constraint1
, Constraint2
, ...
) => ExampleClass (ExampleData xs)
where
type ExampleType (ExampleData xs) = Int
f = undefined
当我将此文件加载到 ghci
ghci> :l Example.hs
编译速度非常快,不到 1 秒。然后,我执行以下行:
ghci> let test = f Int :: ExampleData
没有进行实际的计算,但这仍然需要很长时间。ExampleData
的实例声明中的约束越多,所需的时间就越长。(实际上评估测试稍后会立即发生。)我想出如何调试这些性能问题的最佳方法是逐一注释约束并查看哪些约束导致性能下降。但这非常耗时,而且当这些约束涉及复杂的类型族时,它的信息量并不大。
那么,有没有更好的方法可以用来调试这个问题?
编辑:原来我在 GHC 中发现了一个错误。有一个与该错误相关的脚本,该脚本表明约束求解器在应该是线性的输入上花费二次时间。