В 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. Там script связан с ошибкой, которая показывает, что решатель ограничений принимает квадратичное время на входах, которые должны быть линейными.