[Haskell] randomgen for foreign random functions

Simon Peyton-Jones simonpj at microsoft.com
Mon Jun 28 03:59:24 EDT 2004

| Say I have a foreign function:
| foreign import ccall "statistical_c.h gengam"     c_gengam :: CDouble
-> CDouble -> IO CDouble
| that returns a random value parameterized by the two CDoubles.
| this must happen in IO since the return value will be different each
| and some global state stuff is getting modified on the C side to
| facilitate future random # generation.
| However, I would like to wrap this into an essentially pure function,
| the Random class.  basically, i want to wrap this up as something
| gengam :: RandomGen g => g -> Double -> Double -> (g, Double)
| analogously to the normal random # generation stuff.

There's a standard approach, originally due to Lennart Augustsson.

Have a single function that generates an infinite supply
	mkSupply :: IO Supply

The Supply is a tree
	data Supply = Supply Int Supply Supply

So splitting and generation are easy.  But how do you generate an
infinite tree?  By using your side-effecting function plus
unsafeInterleaveIO.  (This function is better behaved then
unsafePerformIO; no need for NOINLINE nonsense.)

Here's the code from GHC's unique supply (you can ignore all the unboxed
stuff.  The genSymZh thing is the equivalent to your gengam.

You still need the tree so that if you split the same random supply
twice, you get the same thing:
	let (g1,g2) = split g in ..
is the same as
	let g1 = fst (split g); g2 = snd (split g) in ...


mkSplitUniqSupply (C# c#)
  = let
	mask# = (i2w (ord# c#)) `uncheckedShiftL#` (i2w_s 24#)

	-- This is one of the most hammered bits in the whole compiler
	  = unsafeInterleaveIO (
		mk_unique   >>= \ uniq ->
		mk_supply#  >>= \ s1 ->
		mk_supply#  >>= \ s2 ->
		return (MkSplitUniqSupply uniq s1 s2)

	mk_unique = genSymZh		>>= \ (W# u#) ->
		    return (I# (w2i (mask# `or#` u#)))

More information about the Haskell mailing list