packages feed

hat-2.7.0.0: libraries/Random.hs

-- some parts are taken from the nhc98/Hugs implementation of Random
module Random (
  RandomGen(next, split, genRange),
  StdGen, mkStdGen,
  Random( random,   randomR, 
  randoms,  randomRs,
  randomIO, randomRIO ),
  getStdRandom, getStdGen, setStdGen, newStdGen
  ) where

import PreludeBuiltinTypes
import RandomBuiltin
import qualified TraceOrigSystem.Random as TraceOrigRandom
import Char

---------------- The RandomGen class ------------------------

class RandomGen g where
  genRange :: g -> (Int, Int)
  next     :: g -> (Int, g)
  split    :: g -> (g, g)
   
  -- Default method
  genRange g = (minBound,maxBound)

---------------- A standard instance of RandomGen -----------

-- data StdGen = ... -- Abstract

instance RandomGen StdGen where
  genRange = primStdGenGenRange
  next = primStdGenNext
  split = primStdGenSplit

instance Read StdGen where
  readsPrec = primStdGenReadsPrec

instance Show StdGen where
  showsPrec = primStdGenShowsPrec

foreign import haskell "Random.genRange"
 primStdGenGenRange :: StdGen -> (Int,Int)
foreign import haskell "Random.next"
 primStdGenNext :: StdGen -> (Int,StdGen)
foreign import haskell "Random.split"
 primStdGenSplit :: StdGen -> (StdGen,StdGen)
foreign import haskell "Prelude.readsPrec"
 primStdGenReadsPrec :: Int -> String -> [(StdGen,String)]
foreign import haskell "Prelude.showsPrec"
 primStdGenShowsPrec :: Int -> StdGen -> String -> String


foreign import haskell "Random.mkStdGen"
 mkStdGen :: Int -> StdGen

 ---------------- The Random class ---------------------------
class Random a where
  randomR :: RandomGen g => (a, a) -> g -> (a, g)
  random  :: RandomGen g => g -> (a, g)

  randomRs :: RandomGen g => (a, a) -> g -> [a]
  randoms  :: RandomGen g => g -> [a]

  randomRIO :: (a,a) -> IO a
  randomIO  :: IO a
     
  -- Default methods
  randoms g = x : randoms g' 
    where 
    (x,g') = random g
  randomRs range g = x : randomRs range g'
    where
    (x,g') = randomR range g
  randomIO        = getStdRandom random
  randomRIO range = getStdRandom (randomR range)

instance Random Int     where 
  randomR (a,b) g = randomIvalInteger (toInteger a, toInteger b) g
  random g        = randomR (minBound,maxBound) g

instance Random Integer where 
  randomR ival g = randomIvalInteger ival g
  random g	 = randomR (toInteger (minBound::Int), toInteger (maxBound::Int)) g

instance Random Float where
  random g        = randomIvalDouble (0::Double,1) realToFrac g
  randomR (a,b) g = randomIvalDouble (realToFrac a, realToFrac b) realToFrac g

instance Random Double  where 
  randomR ival g = randomIvalDouble ival id g
  random g       = randomR (0::Double,1) g

instance Random Bool where 
  randomR (a,b) g = 
    case 
      (randomIvalInteger (bool2Integer a, bool2Integer b) g) of
        (x, g) -> (int2Bool x, g)
    where
    bool2Integer :: Bool -> Integer
    bool2Integer False = 0
    bool2Integer True  = 1

    int2Bool :: Int -> Bool
    int2Bool 0	= False
    int2Bool _	= True

  random g = randomR (minBound,maxBound) g

instance Random Char where 
  randomR (a,b) g = 
      case (randomIvalInteger (toInteger (ord a), toInteger (ord b)) g) of
        (x,g) -> (chr x, g)
  random g = randomR (minBound,maxBound) g


-- internal:
randomIvalInteger :: (RandomGen g, Num a) => (Integer, Integer) -> g -> (a, g)
randomIvalInteger (l,h) rng
 | l > h     = randomIvalInteger (h,l) rng
 | otherwise = case (f n 1 rng) of (v, rng') -> (fromInteger (l + v `mod` k), rng')
     where
       k = h - l + 1
       b = 2147483561
       n = iLogBase b k

       f 0 acc g = (acc, g)
       f n acc g = 
          let
	   (x,g')   = next g
	  in
	  f (n-1) (fromInt x + acc * b) g'

randomIvalDouble :: (RandomGen g, Fractional a) => (Double, Double) -> (Double -> a) -> g -> (a, g)
randomIvalDouble (l,h) fromDouble rng 
  | l > h     = randomIvalDouble (h,l) fromDouble rng
  | otherwise = 
       case (randomIvalInteger (toInteger (minBound::Int), toInteger (maxBound::Int)) rng) of
         (x, rng') -> 
	    let
	     scaled_x = 
		fromDouble ((l+h)/2) + 
                fromDouble ((h-l) / realToFrac intRange) *
		fromIntegral (x::Int)
	    in
	    (scaled_x, rng')

fromInt :: Num a => Int -> a
fromInt = fromInteger . toInteger

intRange :: Integer
intRange  = toInteger (maxBound::Int) - toInteger (minBound::Int)

iLogBase :: Integer -> Integer -> Integer
iLogBase b i = if i < b then 1 else 1 + iLogBase b (i `div` b)

---------------- The global random generator ----------------

foreign import haskell "Random.newStdGen"
 newStdGen    :: IO StdGen
foreign import haskell "Random.setStdGen"
 setStdGen    :: StdGen -> IO ()
foreign import haskell "Random.getStdGen"
 getStdGen    :: IO StdGen 
foreign import haskell "Random.getStdRandom"
 getStdRandom :: (StdGen -> (a, StdGen)) -> IO a