[Haskell-cafe] Random numbers / monads - beginner question
Hello, I am just learning Haskell. Now, I encountered something that I cannot solve by myself. Your advice will be greatly appreciated. Given a list of numbers, I want to modify each of those numbers by adding a random offset. However, each such modified number shall stay within certain bounds, given by the integers minValue and maxValue. After that, I want to continue computation with the resulting list of type [Int]. But for demonstration, I made a program that just prints out the list: import IO; import Random minValue = 0::Int maxValue = 1000::Int normalize a | a minValue = minValue | a maxValue = maxValue | otherwise = a modify a = do offset - randomRIO(-100::Int, 100) return(normalize(a + offset)) main = putStrLn $ show $ map (modify) [0, 200, 400, 600, 800, 1000] This program will not compile. GHC complains: test.hs:14:18: No instance for (Show (IO Int)) arising from a use of `show' at test.hs:14:18-21 Possible fix: add an instance declaration for (Show (IO Int)) In the first argument of `($)', namely `show' In the second argument of `($)', namely `show $ map (modify) [0, 200, 400, 600, ]' In the expression: putStrLn $ show $ map (modify) [0, 200, 400, 600, ] I understand that the result of the modify function is not an Int, as I would like to have it, but instead IO Int, and that cannot be applied to show. (I also did not quite understand why I need those brackets around the return value of the modify value. It won't compile if I leave them out, but I can accept that for now.) I also figured out how to generate a modified list of type [IO Int] and of type IO [Int]. However, I could not find out how to completely get rid of the IO monad and just get a mofied list of type [Int], which is what I really want. Please, do You have any advice for me? I tried for some hours, and now I am really angry at that IO monad that sticks to my pretty integers like glue! Also, any comment on the programming style and how I could achive my goals easier would be appreciated. (I left out comments and function types for the sake of brevity.) Thanks a lot in advance. Madoc. -- View this message in context: http://www.nabble.com/Random-numbers---monads---beginner-question-tp17124380p17124380.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Random numbers / monads - beginner question
Madoc wrote: Given a list of numbers, I want to modify each of those numbers by adding a random offset. However, each such modified number shall stay within certain bounds, given by the integers minValue and maxValue. After that, I want to continue computation with the resulting list of type [Int]. Personally, I'd do something like this, isolate the IO code outside the algorithm to keep the algorithm pure: modify' :: Int - Int - Int modify' offset a = normalize (a + offset) generateInfiniteListOfRandomNumbers :: IO [Int] -- implementation left as an exercise main = do randomNumbers - generateInfiniteListOfRandomNumbers print $ zipWith modify' randomNumbers [0, 200, 400, 600, 800, 1000] hope this helps, Claude -- http://claudiusmaximus.goto10.org ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Random numbers / monads - beginner question
Madoc wrote: Given a list of numbers, I want to modify each of those numbers by adding a random offset. However, each such modified number shall stay within certain bounds, given by the integers minValue and maxValue. After that, I want to continue computation with the resulting list of type [Int]. Personally, I'd do something like this, isolate the IO code outside the algorithm to keep the algorithm pure: modify' :: Int - Int - Int modify' offset a = normalize (a + offset) generateInfiniteListOfRandomNumbers :: IO [Int] -- implementation left as an exercise main = do randomNumbers - generateInfiniteListOfRandomNumbers print $ zipWith modify' randomNumbers [0, 200, 400, 600, 800, 1000] I may be wrong, but generateInfiniteListOfRandomNumbers won't terminate and I think it has to before the next IO action occurs. (Laziness is great, but I don't think you can really do lazy IO like that.) Instead of map :: (a - b) - [a] - [b], I think you are looking for mapM :: Monad m = (a - m b) - [a] - m [b]. * * * *Hope this helps, Thomas ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Random numbers / monads - beginner question
2008/5/8 Thomas Dinsdale-Young [EMAIL PROTECTED]: Madoc wrote: Given a list of numbers, I want to modify each of those numbers by adding a random offset. However, each such modified number shall stay within certain bounds, given by the integers minValue and maxValue. After that, I want to continue computation with the resulting list of type [Int]. Personally, I'd do something like this, isolate the IO code outside the algorithm to keep the algorithm pure: modify' :: Int - Int - Int modify' offset a = normalize (a + offset) generateInfiniteListOfRandomNumbers :: IO [Int] -- implementation left as an exercise main = do randomNumbers - generateInfiniteListOfRandomNumbers print $ zipWith modify' randomNumbers [0, 200, 400, 600, 800, 1000] I may be wrong, but generateInfiniteListOfRandomNumbers won't terminate and I think it has to before the next IO action occurs. (Laziness is great, but I don't think you can really do lazy IO like that.) Sure it will. You're right that you cannot do lazy IO like this, but no lazy IO needs to happen here. The key is that an IO action does not have to be performed in order to generate each element of the list -- one IO action is performed at the beginning to produce a random generator, and then this generator is used (functionally and purely) to produce a lazy infinite list of pseudorandom numbers. For example see the 'newStdGen' and 'randoms' functions from System.Random. -Brent ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Random numbers / monads - beginner question
On Thu, 8 May 2008, Madoc wrote: Given a list of numbers, I want to modify each of those numbers by adding a random offset. However, each such modified number shall stay within certain bounds, given by the integers minValue and maxValue. After that, I want to continue computation with the resulting list of type [Int]. But for demonstration, I made a program that just prints out the list: import IO; import Random minValue = 0::Int maxValue = 1000::Int normalize a | a minValue = minValue | a maxValue = maxValue | otherwise = a normalize = min maxValue . max minValue modify a = do offset - randomRIO(-100::Int, 100) return(normalize(a + offset)) Stay away from IO whereever possible, use randomR instead. Say map normalize (zipWith (+) (randomRs (-100::Int, 100)) x) http://haskell.org/haskellwiki/Humor/Erlkönig http://haskell.org/haskellwiki/Things_to_avoid#Separate_IO_and_data_processing___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Random numbers / monads - beginner question
2008/5/8 Madoc [EMAIL PROTECTED]: Hello, I am just learning Haskell. Now, I encountered something that I cannot solve by myself. Your advice will be greatly appreciated. Given a list of numbers, I want to modify each of those numbers by adding a random offset. However, each such modified number shall stay within certain bounds, given by the integers minValue and maxValue. After that, I want to continue computation with the resulting list of type [Int]. But for demonstration, I made a program that just prints out the list: import IO; import Random minValue = 0::Int maxValue = 1000::Int normalize a | a minValue = minValue | a maxValue = maxValue | otherwise = a modify a = do offset - randomRIO(-100::Int, 100) return(normalize(a + offset)) main = putStrLn $ show $ map (modify) [0, 200, 400, 600, 800, 1000] This program will not compile. GHC complains: test.hs:14:18: No instance for (Show (IO Int)) arising from a use of `show' at test.hs:14:18-21 Possible fix: add an instance declaration for (Show (IO Int)) In the first argument of `($)', namely `show' In the second argument of `($)', namely `show $ map (modify) [0, 200, 400, 600, ]' In the expression: putStrLn $ show $ map (modify) [0, 200, 400, 600, ] I understand that the result of the modify function is not an Int, as I would like to have it, but instead IO Int, and that cannot be applied to show. (I also did not quite understand why I need those brackets around the return value of the modify value. It won't compile if I leave them out, but I can accept that for now.) I also figured out how to generate a modified list of type [IO Int] and of type IO [Int]. However, I could not find out how to completely get rid of the IO monad and just get a mofied list of type [Int], which is what I really want. Please, do You have any advice for me? I tried for some hours, and now I am really angry at that IO monad that sticks to my pretty integers like glue! Also, any comment on the programming style and how I could achive my goals easier would be appreciated. (I left out comments and function types for the sake of brevity.) You should use newStdGen to produce a random generator, then randomRs to produce a list of random numbers (without using IO!). But if you really want this version with IO interspersed through the algorithm to work, then something like this should do it (uncompiled): main = do xs - mapM (modify) [0, 200, 400, 600, 800, 1000] putStrLn $ show $ xs The only way to get rid of the IO monad, is to use - to bind it to a value from within the IO monad. -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862 ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Random numbers / monads - beginner question
Henning Thielemann wrote: On Thu, 8 May 2008, Madoc wrote: minValue = 0::Int maxValue = 1000::Int normalize a | a minValue = minValue | a maxValue = maxValue | otherwise = a normalize' = min maxValue . max minValue There is a curiosity here. The functions normalize and normalize' are extensionally equal only because minValue = maxValue, but intensionally different. The intensional equivalent is to reverse order of composition: normalize'' = max minValue . min maxValue which remains equal to to normalize whatever the values of minValue and maxValue. That the order of composition (or of guarded expressions) matters conditionally base on its parameters is reason enough for the original poster to decide what the right answer should be if maxValue minValue. These corner cases are often where future bugs lie dormant. My choice would be: normalize'''= max trueMin . min trueMax where trueMin = min minValue maxValue trueMax = max minValue maxValue Now the function makes no assumptions about external values. This is no less efficient than before, since trueMin and trueMax are CAFs evaluated only once. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe