Simulating the martingale betting system with roulette
Is it more natural for functions that compute random variable x to require StdGens as an argument, or for them to create StdGens and perhaps return IO x?


I think in most cases you're going to be better off passing around a pure source of randomness or a seed value so that you can guarantee deterministic output if need be by using the same seed in multiple runs. That is, you made the right choice.


  Also, is my source code posted below reasonable and could it be improved or made more natural?


I don't think there's anything wrong per se, but it's very narrowly focused without much opportunity for reusability. You'll not often go wrong if you attempt to mirror the reality of what you're modeling in your functions and type signatures. For instance, consider that a roulette wheel is an unlimited source of randomly chosen values. One way to express this in your Haskell program would be...

wheel :: StdGen -&gt; [Int]
wheel = randomRs (0, 37)


It's useful to encapsulate this because there's nothing about martingale betting systems that involves a random element, the system itself is entirely deterministic.

martingale :: Int        -- ^ Current bet
           -&gt; Bool       -- ^ Result of current spin
           -&gt; (Int, Int) -- ^ (Next bet, winnings/losings)
martingale bet True  = (1      ,        bet)
martingale bet False = (bet * 2, negate bet)


Here I've separated out just the betting system aspect of your program, because tracking winnings or choosing ranges are separate functions from determining bets. This way also you can substitute different betting strategies fairly easy as long as it has the same type signature.

You'd tie this all together with a simulation function something like this.

simulate :: (Int -&gt; Bool)               -- ^ A picking function
         -&gt; (Int -&gt; Bool -&gt; (Int, Int)) -- ^ A betting function
         -&gt; Int                         -- ^ An initial bet
         -&gt; (Int -&gt; Maybe Bool)         -- ^ Decides when to leave the table
         -&gt; [Int]                       -- ^ A wheel
         -&gt; Bool                        -- ^ Took winnings or unacceptable loss?


This is probably way overkill to start with, but with it you could test biased wheels, or different levels of acceptable losses, or different strategies against particular wheels. At this point also you'd want to start using type aliases, newtypes, or your own data types to disambiguate what's going on. E.g., you'd end up with...

simulate :: (Slot -&gt; Bool)
         -&gt; (Stake -&gt; Bool -&gt; (Stake, Winnings))
         -&gt; Stake
         -&gt; (Winnings -&gt; PlayState)
         -&gt; [Slot]
         -&gt; PlayState


And used like,

simulate betOnRed martingale 1 quitWhileAhead unbiasedWheel
simulate betOnLow antimartingale 50 bailBelowFifty houseBiasedWheel