title: Procedurally generating large list of values in Haskell -- most idiomatic approach? memory management?
body: <p>I have a function that takes a series of random numbers/floats, and uses them to generate a value/structure (ie, taking a random velocity and position of the point a ball is thrown from and outputting the coordinates of where it would land).  And I need to generate several thousands in succession.</p>
  
  <p>The way I have everything implemented is each calculation takes in an stdGen, uses it to generate several numbers, and passes out a new stdGen to allow it to be chained to another one.</p>
  
  <p>And to do this for 10000 items, I make a sort of list from <code>generate_item n</code> which basically outputs a <code>(value,gen)</code> tuple (the value being the value i'm trying to calculate), where the value of <code>gen</code> is the recursively outputted stdGen from the calculations involved in getting the value from <code>generate_item n-1</code></p>
  
  <p>However, this program seems to crawl to be impractically slow at around a thousand results or so.  And seems to definitely not be scalable.  Could it have to do with the fact that I am storing all of the <code>generate_item</code> results in memory?</p>
  
  <p>Or is there a more idomatic way of approaching this problem in Haskell using Monads or something than what I have describe above?</p>
  
  <p>Note that the code to generate the algorithm from the random value generates 10k within seconds even in high-level scripting languages like ruby and python; these calculations are hardly intensive.</p>
  
  <p>Code</p>
  
  <pre><code>-- helper functions that take in StdGen and return (Result,new StdGen)
  plum_radius :: StdGen -&gt; (Float,StdGen)
  unitpoint   :: Float -&gt; StdGen -&gt; ((Float,Float,Float),StdGen)
  plum_speed  :: Float -&gt; StdGen -&gt; (Float,StdGen)
  
  -- The overall calculation of the value
  plum_point  :: StdGen -&gt; (((Float,Float,Float),(Float,Float,Float)),StdGen)
  plum_point gen  = (((px,py,pz),(vx,vy,vz)),gen_out)
    where
      (r, gen2)         = plum_radius gen
      ((px,py,pz),gen3) = unitpoint r gen2
      (s, gen4)         = plum_speed r gen3
      ((vx,vy,vz),gen5) = unitpoint s gen4
      gen_out           = gen5
  
  -- Turning it into some kind of list
  plum_data_list  :: StdGen -&gt; Int -&gt; (((Float,Float,Float),(Float,Float,Float)),StdGen)
  plum_data_list seed_gen 0  = plum_point seed_gen
  plum_data_list seed_gen i  = plum_point gen2
    where
      (_,gen2)  = plum_data_list seed_gen (i-1)
  
  -- Getting 100 results
  main = do
    gen &lt;- getStdGen
    let data_list = map (plum_data_list gen) [1..100]
    putStrLn List.intercalate " " (map show data_list)
  </code></pre>