| 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. clearly | this must happen in IO since the return value will be different each time, | 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, ala | the Random class. basically, i want to wrap this up as something like: | | 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 ... Simon mkSplitUniqSupply (C# c#) = let mask# = (i2w (ord# c#)) `uncheckedShiftL#` (i2w_s 24#) -- This is one of the most hammered bits in the whole compiler mk_supply# = 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#))) in mk_supply# _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell