Optimize MonadUnique instances based on IO.
Currently all these instances work by carrying around with them a UniqSupply which is split as needed with the supply being split/updated as needed.
For example here is the implementation for IOEnv:
newUnique :: TcRnIf gbl lcl Unique
newUnique
= do { env <- getEnv ;
let { u_var = env_us env } ;
us <- readMutVar u_var ;
case takeUniqFromSupply us of { (uniq, us') -> do {
writeMutVar u_var us' ;
return $! uniq }}}
When really we could just call the number generator directly and apply the mask.
So this should instead be something like:
newUnique :: TcRnIf gbl lcl Unique
newUnique
= do { env <- getEnv;
let uniqMask = env_uqMask env;
uqNum <- genSym;
return $! mkUniqGrimly (uqNum .|. uniqMask)}
See mkSplitUniqSupply of the details about the mask/genSym.
This would eliminate per invocation:
- Writing an IORef
- Reading an IORef
- Allocating a new UniqSupply constructor.
The same applies to other Monads operating over IO like CoreM.
Some of them use a static unique category as well so the mask could be hard coded which is even better!