Есть ли какой-нибудь способ заставить GHC выполнять определенные вычисления в течение всего времени жизни определенного значения?
Очевидно, я мог бы поместить значение в запись, создав ленивые записи для результата указанного вычисления, и создать функцию создателя, которая создает запись и преобразует значение в указанные записи.
Однако мне не хотелось бы каждый раз извлекать исходное значение из записи. А в Haskell нет полиморфных -взаимосвязей, подобных C++ или Java.
Есть ли какой-нибудь трюк для запоминания значений при нескольких несвязанных вызовах функции с одинаковыми параметрами?
Я мог смутно представить себе различные трюки с формами зависимых типов, которые эффективно сообщали бы компилятору о предстоящем многократном использовании. В Haskell нет зависимых типов, но, может быть, что-то с неявными параметрами? Полагаю, нет, но я подумал, что спрошу. Может, прагма?
Представьте, что у меня есть вектор из Necklace
структур данных, для которого мне нужен результирующий вектор рациональных чисел, сохраненный как общий знаменатель, и вектор числителей.
{-# LANGUAGE ImplicitParams #-}
import qualified Data.Vector as V
data Necklace = Necklace {... }
necklace_length n =...
denominator :: (necklaces :: V.Vector Necklace) => Int
denominator = V.foldl' lcm 30 $ V.map necklace_length ?necklaces
numerators :: (necklaces :: V.Vector Necklace) => V.Vector Int
numerators = V.map f ?necklaces
where f x =... denominator...
kittytoy :: (necklaces :: V.Vector Necklace) => Meow ->...
kittytoy = \meow ->... numerators...
Априори я ожидаю, что если я вызову kittytoy
несколько миллионов раз, каждый с другим параметром meow
, то GHC создаст код, который вызовет numerators
миллион раз, каждый с одинаковыми неявными параметрами. necklaces
.
Тем не менее очевидно, что numerators
нужно вызывать только один раз, при первом назначении ?necklaces
, а это означает, что GHC потенциально может заметить эту оптимизацию.
Должен быть даже явный подход к рефакторингу кода с использованием шаблона haskell для явной передачи переходников путем создания кода вроде ?numerators = numerators
и добавления numerators :: V.Vector Int
к ограничениям типов функций, которые его вызывают.