1

Still a beginner that can't figure out a recursive loop in an IO action. Assume:

fMinInspect :: Int
fMinInspect = 1
fMaxInspect :: Int
fMaxInspect = 12
-- fNoInspectPerHour :: IO ()
fNoInspectPerHour = do
  generateInspect <- randomRIO (fMinInspect,fMaxInspect)
  putStrLn ""

I would like to generate a list for let's say 10 machines I want randomly checked, can I then make a repeated call to something that would add 10x fNoInspectPerHour to a list?

I tried an external function, but I can't get the actions from the IO (). Note that putStrLn is just to terminate the do-block, since I don't need console output.

PS. suggestions on terminating a do-block without the putStrLn is welcome too.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Madderote
  • 1,107
  • 10
  • 19
  • 2
    Just use `return ()`; that's the simplest way to create an `IO ()` value. – chepner Oct 22 '18 at 14:48
  • 1
    Otherwise, it's not clear what you want. Do you want a list of 10 random numbers? – chepner Oct 22 '18 at 14:51
  • As is, `fNoInspectPerHour` doesn't really do anything except modify the state of the random number generator; it doesn't do anything with the random number it generates. – chepner Oct 22 '18 at 14:52

2 Answers2

1

randomIO (fMinInspect, fMaxInspect) is an IO action, a value of type (Num a, Random a) => IO a. (For simplicity, we'll assume that a is Int from now on.) Note that each execution of the action can generate a different random value; that's the difference between IO Int being an action that generates a random value and being a random value itself.

Once we have that action, we can create a list of actions with replicate 10 (randomRIO (fMinInspect, fMaxInspect)); this will have type [IO Int], 10 copies of an IO action.

The sequence function can change your list of IO actions into an IO action that yields a list of values (each value being produced by the corresponding action), converting a value of type [IO Int] into a value of type IO [Int].

> fMinInspect = 1
> fMaxInspect = 12
> sequence (replicate 10 (randomRIO (fMinInspect, fMaxInspect)))
[1,6,6,1,7,5,8,4,7,7]

(Here, as usual, GCHi is executing the IO action, which was produced by sequence, and returns the result produced by that IO action.)

Will Ness
  • 70,110
  • 9
  • 98
  • 181
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 1
    ...and this combination of `sequence` and `replicate` is so common that it's got a standard name, `replicateM`. – Daniel Wagner Oct 22 '18 at 15:15
  • Oh, I thought that existed, but it didn't seem to be in scope. I had to import `Control.Monad` first. – chepner Oct 22 '18 at 15:22
  • Thanks @Chepner and Daniel Wagner. That certainly helped me out.. Still got a lot to learn. Haskell's trying to keep it interesting. – Madderote Oct 22 '18 at 15:37
  • By the way @Chepner: your example works from the prompt, but how to incorporate in the do-block....? – Madderote Oct 22 '18 at 15:46
  • Why do you need a `do` block? It's still not clear what the purpose of `fNoInspectPerHour` is, since it doesn't do anything with the generated number. – chepner Oct 22 '18 at 15:54
  • I mean, you can write `replicateM 3 fNoInspectPerHour` to get a value of `IO [(), (), ()]`, but unless you actually yield each random number, what's the point? – chepner Oct 22 '18 at 16:01
  • @Madderote you can write `fNoInspectPerHour = do { generateInspectList <- sequence (replicate 10 (randomRIO (fMinInspect,fMaxInspect))) ; print generateInspectList }` if that's what you meant to do. – Will Ness Oct 22 '18 at 17:20
  • @Chepner, first need to get them before I can use them, but your insights and those of Will Ness already helped solving it. I am apparently struggling also with the number of ways to address problems in Haskell. Thanks!! – Madderote Oct 23 '18 at 06:44
  • @Madderote great to hear that it helps. Keep at it, keep asking on SO (and elsewhere), and keep keeping engaged on your questions! :) – Will Ness Oct 23 '18 at 06:48
1

If you actually meant to use recursion yourself here, you could write e.g.

fNoInspectPerHour :: Int -> IO () 
fNoInspectPerHour 0 = return () 
fNoInspectPerHour n = do { 
    generateInspect <- randomRIO (fMinInspect,fMaxInspect) ; 
    --  Int            IO Int
    putStrLn generateInspect ;    -- or do some other IO action
    --                 IO ()
    fNoInspectPerHour (n-1) 
    --                 IO ()
    }
Will Ness
  • 70,110
  • 9
  • 98
  • 181