I am currently working on some transactional memory benchmarks in Haskell and would like to be able to make use of random numbers within a transaction. I am currently making use of the Random monad/monad transformer from here. In the following example, I have an array of TVars containing integers and a transaction that randomly selects 10 tvars in the array to increment, such as:
tvars :: STM (TArray Int Int)
tvars = newArray (0, numTVars) 0
write :: Int -> RandT StdGen STM [Int]
write 0 = return []
write i = do
tvars <- lift tvars
rn <- getRandomR (0, numTVars)
temp <- lift $ readArray tvars rn
lift $ writeArray tvars rn (temp + 1)
rands <- write (i-1)
lift $ return $ rn : rands
I guess my question is "Is this the best way to go about doing this?" It seems like it would be more natural/efficient to go the other way around, i.e. lift the random monad into the STM monad. Each transaction does a lot of STM operations, and very few random operations. I would assume that each lift adds some amount of overhead. Wouldn't it be more efficient to only lift the random computations and leave the STM computations alone? Is this even safe to do? It seems that defining an STM monad transformer would break the nice static separation properties that we get with the STM monad (i.e. We could lift IO into the STM monad, but then we have to worry about undoing IO actions if a transaction aborts which presents a number of issues). My knowledge of monad transformers if pretty limited, a brief explanation regarding the performance and relative overhead of using a transformer would be much appreciated.
Aucun commentaire:
Enregistrer un commentaire