I finally decided to actually solve the problem, and I'm sorry to say I was on the wrong track. ListT won't do it on its own: you actually need a custom monad that does the random pick in the bind operation. Attached are a module to solve the problem and a Main module that tests it. I hope this helps.

Paul.
-- | Test the MonteCarlo Monad

module Main where

import System.Random
import MonteCarlo


f, g :: Int -> MonteCarlo Int
f x = returnList $ map (*3) [x .. x+( x `mod` 5)-1]

g x = returnList $ map (*2) [x .. x+( x `mod` 7)-1]


-- The actual Monte-Carlo computation
experiment :: [Int] -> MonteCarlo (Int, Int, Int)
experiment xs = do
   x  <- returnList xs
   f1 <- f x
   g1 <- g x
   return (x, f1, g1)


-- Infinite list of generators
generators :: StdGen -> [StdGen]
generators g = g1 : generators g2
   where (g1, g2) = split g


main :: IO ()
main = do
   g <- getStdGen
   print $ take 10 $ map (runMonteCarlo $ experiment [1..100]) $ generators g


-- | A monad of random non-determinism.  Each action in the computation
-- generates zero or more results.  Zero is failure, but if more than one
-- result is returned then one is selected at random.

module MonteCarlo (
   MonteCarlo,
   runMonteCarlo,
   returnList
) where

import Control.Monad
import System.Random

newtype MonteCarlo a = MonteCarlo {runMC :: StdGen -> (StdGen, [a])}


-- | Run a Monte-Carlo simulation to generate a zero or one results.
runMonteCarlo :: MonteCarlo a -> StdGen -> Maybe a
runMonteCarlo (MonteCarlo m) g1 =
   let
      (g2, xs) = m g1
      (_,  x)  = pickOne xs g2
   in case xs of
      []   -> Nothing
      [x1] -> Just x1
      _    -> Just x


-- Internal function to pick a random element from a list
pickOne :: [a] -> StdGen -> (StdGen, a)
pickOne xs g1 = let (n, g2) = randomR (0, length xs - 1) g1 in (g2, xs !! n)


instance Monad MonteCarlo where
   MonteCarlo m >>= f  = MonteCarlo $ \g1 -> 
      let -- If I was clever I'd find a way to merge this with runMonteCarlo.
         (g2, xs)  = m g1
         (g3, x)   = pickOne xs g2
         f'        = case xs of
                        []   -> mzero
                        [x1] -> f x1
                        _    -> f x
      in runMC f' g3

   return x = MonteCarlo $ \g -> (g, [x])
   

instance MonadPlus MonteCarlo where
   mzero = MonteCarlo $ \g -> (g, [])
   mplus (MonteCarlo m1) (MonteCarlo m2) = MonteCarlo $ \g ->
      let
        (g1, xs1) = m1 g
        (g2, xs2) = m2 g1
      in (g2, xs1 ++ xs2)


-- | Convert a list of items into a Monte-Carlo action.
returnList :: [a] -> MonteCarlo a
returnList xs = MonteCarlo $ \g -> (g, xs)
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to