randomgen for foreign random functions
Hi All -- 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. is there a safe way to do this? one option, of course, is just to unsafePerformIO it and {-# NOINLINE #-} the call, but that is rather, uhm, unsafe, I believe. it seems to me that something like this should be possible. Any thoughts? - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume
Hal Daume III wrote:
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.
is there a safe way to do this? one option, of course, is just to unsafePerformIO it and {-# NOINLINE #-} the call, but that is rather, uhm, unsafe, I believe. it seems to me that something like this should be possible.
Any thoughts?
What were you planning on doing with the "g" parameter? In order to (safely) have the above type, the behaviour of gengam would have to be such that, if called repeatedly with the same arguments (including the g), it would return the same (g, Double) tuple each time. AFAICT, unless you can get at c_gengam's state, you can't (safely) get the Haskell version out of the IO monad. OTOH, if you have a means to set the seed, you could combine the two into a pure function, and thus provide a pure (non-IO) Haskell interface. E.g. if you had: void seedgam(int seed) { srand(seed); } double gengam(double lo, double hi) { return lo + rand() * (hi - lo) / RAND_MAX; } you could either combine them in C: double do_gengam(int seed, double lo, double hi) { seedgam(seed); return gengam(lo, hi); } import that as a pure function: foreign import ccall "statistical_c.h do_gengam" c_do_gengam :: CInt -> CDouble -> CDouble -> CDouble and interface to it as: gengam g lo hi = (g', c_gengam seed lo hi)) where (seed, g') = next g or import them individually as: foreign import ccall "statistical_c.h seedgam" c_seedgam :: CInt -> IO () foreign import ccall "statistical_c.h gengam" c_gengam :: CDouble -> CDouble -> IO CDouble and (safely) use unsafePerformIO, e.g. gengam g lo hi = (g', x) where x = unsafePerformIO $ do seedgam seed x <- c_gengam lo hi (seed, g') = next g [Although, in the second approach, I presume that you would need addtional code for multi-threaded use.] -- Glynn Clements <glynn.clements@virgin.net>
What were you planning on doing with the "g" parameter?
Well, one thought would be to use some type class magicery to try to use this to ensure linearity, but I have no idea how to go about that. Another thing that had crossed my mind was to use unsafeInterleaveIO to generate an infinite list of random #s according to the IO function and store these in g and then just take 1 off the head at each call...I don't know whether this is safe or not, though.
AFAICT, unless you can get at c_gengam's state, you can't (safely) get the Haskell version out of the IO monad. OTOH, if you have a means to set the seed, you could combine the two into a pure function, and thus provide a pure (non-IO) Haskell interface. E.g. if you had:
Hrm. Getting at its state is really a bother and, while I probably could, it would make me a very unhappy camper.
[Although, in the second approach, I presume that you would need addtional code for multi-threaded use.]
I don't care about multi-threaded use. - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume
On Fri, 2004-06-25 at 12:42, Hal Daume III wrote:
Hi All --
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.
You could use an Arbitrary Splittable Supplies library. See "ioSupply" on: http://csg.lcs.mit.edu/~earwig/haskell-lib/index.html You identify two reasons you need IO here (state and foreign function call). Unfortunately, it sounds like they're not so easily separable in this case (unless you're always passing in the same two Double arguments, but I suspect you aren't). So, you could use unsafePerformIO along with the library above, or you could look at the source code (which also uses unsafePerformIO internally) and figure out how to poach bits as appropriate. -Jan-Willem Maessen
is there a safe way to do this? one option, of course, is just to unsafePerformIO it and {-# NOINLINE #-} the call, but that is rather, uhm, unsafe, I believe. it seems to me that something like this should be possible.
Any thoughts?
- Hal
participants (3)
-
Glynn Clements -
Hal Daume III -
Jan-Willem Maessen