Phineas Greene
Phineas Greene

Reputation: 63

Store "constants" without reevaluating them in Haskell

I'm tinkering with a program evaluating optimal yahtzee play. Something that will need to be done often is performing a given task for every possible roll. The following function creates a list that contains all possible rolls, which will be mapped over frequently.

type Roll = [Int]

rollspace :: Int -> [Roll]
rollspace depth = worker [[]] 0
      where m xs n      = map (\e -> n:e) xs
            addRoll xs  = m xs 1 ++ m xs 2 ++ m xs 3 ++ m xs 4 ++ m xs 5 ++ m xs 6
            worker xs i = if i == depth then xs else worker (addRoll xs) (i+1)

This function works as intended, and produces a list of 7776 items when run with a depth of 5. However, it seems terribly inefficient to generate the list of all rolls at a given depth any time it is needed, especially because the depths will only be in the range 1-5. Is there and way to store the rollspace lists for the needed depths and reference them without reevaluating, or does Haskell compile away this issue?

Upvotes: 1

Views: 80

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 153287

Is there and way to store the rollspace lists for the needed depths and reference them without re-evaluating?

Yes, sure, and it's even technology you already know.

rollspace5 :: [Roll]
rollspace5 = rollspace 5

rollspace4 :: [Roll]
rollspace4 = rollspace 4
-- etc.

If it's important that you have a "function-like" object that accepts a number as input -- i.e. rather than knowing statically that you want depth 5 -- you have a few options, including:

rollspaceStored :: Int -> [Roll]
rollspaceStored 5 = rollspace5
rollspaceStored 4 = rollspace4
-- etc.
rollspaceStored other = rollspace other

rollspaceMap :: IntMap [Roll]
rollspaceMap = fromList [(n, rollspace n) | n <- [0..5]]

There are also packages on Hackage for memoization more generally; that search term should be enough to find them.

Upvotes: 7

Related Questions