Search code examples
haskellsumcomplexity-theoryprobabilitymemoization

How to avoid recomputation of a pure function with the same parameters?


I have the following function that convert a list of counts to a discrete probability density function:

freq2prob l = [ (curr / (sum l))) | curr <- l ]

Unfortunately (sum l) is computed for each of the l elements making the computational complexity unnecessarily high.

What is the most concise, elegant, "haskellic" way to deal with this?


Solution

  • It's simple:

    freq2prob l = [ curr / s | let s = sum l, curr <- l ] 
    

    you can put it outside the list comprehension as well: freq2prob l = let s = sum l in [ curr / s | curr <- l ] (notice the in). This is effectively the same computation.

    That is because the first is essentially translated into

    freq2prob :: (Fractional a) => [a] -> [a]
    freq2prob l = [ curr / s | let s = sum l, curr <- l ] 
     = do
         let s = sum l
         curr <- l
         return (curr / s)
     = let s=sum l in
       l >>= (\curr -> [curr / s])
       -- concatMap (\curr -> [curr / s]) l
       -- map (\curr -> curr / s) l
    

    and the second, obviously, to the same code,

    freq2prob l = let s = sum l in [ curr / s | curr <- l ]
     = let s = sum l in
       do
         curr <- l
         return (curr / s)
     = let s=sum l in
       l >>= (\curr -> [curr / s])