Подтвердить что ты не робот

Отладка проблем с производительностью компиляции, вызванных решателем ограничений GHC

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

4b9b3361

Ответ 1

Для чего это стоит, вы можете оценивать ограничения по одному, используя: kind! чтобы узнать, сколько времени потребуется, вместо того, чтобы комментировать их индивидуально.