{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

-- |
-- Module      : Systen.Random.MemoRandom
-- Description : Memoized random number generation
-- Copyright   : © 2015 Johan Kiviniemi
-- License     : MIT
-- Maintainer  : Johan Kiviniemi <devel@johan.kiviniemi.name>
-- Stability   : provisional
-- Portability : TypeFamilies, TypeOperators
--
-- A library for generating random numbers in a memoized manner. Implemented as
-- a lazy table indexed by serialized 'StdGen'. Monomorphism is used to
-- facilitate memoization, users should adapt their design to work with random
-- 'Int' values only.
module System.Random.MemoRandom (randomR', random') where

import Data.MemoTrie
import System.Random

newtype StdGen' = StdGen' { unStdGen' :: StdGen }

instance HasTrie StdGen' where
  newtype StdGen' :->: a = StdGenTrie' (String :->: a)
  trie f = StdGenTrie' (trie (f . StdGen' . read))
  untrie (StdGenTrie' t) = untrie t . show . unStdGen'
  enumerate (StdGenTrie' t) = [ (StdGen' (read a), b) | (a,b) <- enumerate t ]

-- | A memoized variant of 'randomR'.
randomR' :: (Int, Int) -> StdGen -> (Int, StdGen)
randomR' ival = memo2 (\ival' -> randomR ival' . unStdGen') ival . StdGen'

-- | A memoized variant of 'random'.
random' :: StdGen -> (Int, StdGen)
random' = memo (random . unStdGen') . StdGen'