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
实例声明中的约束越多,所需的时间就越长。 (实际上后来评估测试会立即发生。)我弄清楚如何调试这些性能问题的最好方法是逐个注释掉约束并查看哪些因素导致了性能损失。但这是非常耗时的,当这些限制涉及复杂类型的家庭时,它并不是真正的信息。
那么,我可以采用更好的方法来调试这个问题吗?
编辑:事实证明我发现了bug in GHC。有一个与该bug相关联的脚本,表明约束求解器在输入上采用二次时间应该是线性的。
答案 0 :(得分:7)
对于它的价值,您可以使用以下方法一次评估约束:亲切!看看需要多长时间,而不是需要单独评论它们。