Well, the simplest solution I can think of is below. The OtherNormalStateT doesn't actually have any state at all, but still gets state from the StateT 'below' it and returns a result.
This is still a bit ugly, but it compiles - and although I haven't tested it properly yet, simply implementing the 'other' helper function to do the work should be fine.
It's a question of how smart the compiler is. Obviously this is inefficient in theory, but will the compiler notice we are passing around a 'unit' state and that the s -> (a,s) function doesn't care about the input.... perhaps. I'd expect the overhead from this to be fairly small and it does allow me to continue using the same paradigm for stateless versions of my normal generator.
I have seen people do similar things when they wish to carry around state but have no result, and thus the result is set to (). I can't see why this is any less inefficient than that?
type BoxMullerStateT = StateT (Maybe Double)
type BoxMullerRandomStateStack = BoxMullerStateT MyRngState
instance NormalClass BoxMullerRandomStateStack where
generateNormal = StateT $ \s -> case s of
Just d -> return (d,Nothing)
Nothing -> do qrnBaseList <- nextRand
let (norm1,norm2) = boxMuller (head qrnBaseList) (head $ tail qrnBaseList)
return (norm1,Just norm2)
-- New stateless StateT below!
type OtherNormalStateT = StateT ()
type OtherRandomStateStack = OtherNormalStateT MyRngState
instance NormalClass OtherRandomStateStack where
generateNormal = StateT $ \_ -> do rn:rns <- nextRand
return ( other rn, () )