У меня каверзный вопрос;
Итак, я знаю, что GHC будет «кэшировать» (из-за отсутствия лучшего термина) определения верхнего уровня и вычислять их только один раз, например. :
myList :: [Int]
myList = fmap (*10) [0..10]
Даже если я использую myList
в нескольких местах, GHC замечает, что значение не имеет параметров, поэтому оно может поделиться им и не будет «перестраивать» список.
Я хочу сделать это, но с вычислением, которое зависит от контекста уровня типа; упрощенный пример:
dependentList :: forall n. (KnownNat n) => [Nat]
dependentList = [0..natVal (Proxy @n)]
Итак, здесь интересно то, что для dependentList
не существует «одиночного» кэшируемого значения; но как только тип применяется, он сводится к константе, поэтому теоретически, когда запускается средство проверки типов, GHC может распознать, что несколько точек зависят от «одного и того же» dependentList
; например (с использованием TypeApplications)
main = do
print (dependentList @5)
print (dependentList @10)
print (dependentList @5)
У меня вопрос: признает ли GHC, что он может использовать оба списка 5
? Или он вычисляет каждый отдельно? Технически было бы даже возможно вычислить эти значения во время компиляции, а не во время выполнения, возможно ли заставить GHC сделать это?
Мой случай немного сложнее, но он должен следовать тем же ограничениям, что и в примере, однако мое dependentList
-подобное значение требует больших вычислений.
Я вовсе не против того, чтобы делать это с использованием класса типов, если это делает возможным; GHC кеширует и повторно использует словари классов типов? Может быть, я мог бы превратить это в константу в dict класса типов, чтобы получить кеширование?
Идеи у кого-нибудь? Или кто-нибудь читает мне, как это работает?
Я бы предпочел сделать это таким образом, чтобы компилятор мог понять это, а не использовать ручное запоминание, но я открыт для идей:)
Спасибо за ваше время!