Suppose that someone would translate this simple Python code to Haskell:
def important_astrological_calculation(digits):
# Get the first 1000000 digits of Pi!
lucky_numbers = calculate_first_digits_of_pi(1000000)
return digits in lucky_numbers
Haskell version:
importantAstrologicalCalculation digits =
isInfixOf digits luckyNumbers
where
luckyNumbers = calculateFirstDigitsOfPi 1000000
After working with the Haskell version, the programmer is astonished to discover that his Haskell version "leaks" memory - after the first time his function is called, luckyNumbers
never gets freed. That is troubling as the program includes some more similar functions and the memory consumed by all of them is significant.
Is there an easy and elegant way to make the program "forget" luckyNumbers
?
Three ways to solve this (based on this blog post)
INLINE
pragmasAdd {-# INLINE luckyNumbers #-}
and another for importantAstrologicalCalculation
.
This will make separate calls be independent from each other, each using their own copy of the luckyNumbers
which is iterated once and is immediately collected by the GC.
Pros:
Cons:
-fno-full-laziness
GHC flagWrap luckyNumbers
with a dummy lambda and use -fno-full-laziness
:
{-# OPTIONS -fno-full-laziness #-}
luckyNumbers _ = calculateFirstDigitsOfPi 1000000
Without the flag, GHC may notice that the expression in luckyNumbers
doesn't use its parameter and so it may float it out and share it.
Pros:
Cons:
-fno-full-laziness
Alonzo Church famously discovered that data can be encoded in functions, and we can use it to avoid creating data structures that could be shared.
luckyNumbers
can be made to a function folding over the digits of pi rather than a data structure.
Pros:
Cons: