'Trying to use an Int RandomIO val in my chart
I am new to monads in Haskell.
I was trying to write a scatter graph with Haskell-chart that would plot 20 points with strong (but not perfect) positive correlation. Example of what I was trying to do. Specifically, I want a list of random doubles in the range 0.8 to 1.0 to multiply with my y-vals to reduce the correlation coefficient a bit. My original implementation was this:
import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo
import System.Random
import Lib (xvals)
main = toFile def "chart.png" $ do
layout_title .= "My chart"
layout_x_axis . laxis_override .= axisGridHide
plot (points "My points" [(x,y) | (x,y) <- let vs = xvals 20 0.0 10.0 in zip vs $ zipWith (*) vs noise])
where noise = filter (>0.8) $ randoms $ mkStdGen 1
which worked, but had the flaw that since the seed for mkStdGen was static, I would get the same points regardless of how many times I rebuilt and executed the code. So I tried this to generate a dynamic seed:
import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo
import System.Random
import Lib (xvals)
main = toFile def "chart.png" $ do
layout_title .= "My chart"
layout_x_axis . laxis_override .= axisGridHide
seed <- (randomIO :: IO Int)
plot (points "My points" [(x,y) | (x,y) <- let vs = xvals 20 0.0 10.0 in zip vs $ zipWith (*) vs noise)])
where noise = filter (>0.8) $ randoms $ mkStdGen seed
The error message I get for the above is:
• Couldn't match type ‘IO’
with ‘transformers-0.5.6.2:Control.Monad.Trans.State.Lazy.StateT
(Layout Double Double)
(transformers-0.5.6.2:Control.Monad.Trans.State.Lazy.State CState)’
Expected type: transformers-0.5.6.2:Control.Monad.Trans.State.Lazy.StateT
(Layout Double Double)
(transformers-0.5.6.2:Control.Monad.Trans.State.Lazy.State CState)
Int
Actual type: IO Int
I think it is due to toFile def "chart.png" but I don't know why, or how to get this working with randomIO. As far as I know, seed :: Int so this should work. Any help would be appreciated.
Solution 1:[1]
If anyone is interested, I got this working with MonadRandom and @jpmarinier's suggestion and @chi's suggestion to use lets instead of wheres:
import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo
import Control.Monad.Random.Class
import Lib (xvals)
main = do
rands <- (getRandoms :: MonadRandom m => m [Double])
toFile def "chart.png" $ do
layout_title .= "My chart"
layout_x_axis . laxis_override .= axisGridHide
let noise = filter (>0.8) rands
let xs = xvals 20 0.0 10.0
let ys = zipWith (*) xs noise
plot (points "My points" [(x,y) | (x,y) <- zip xs ys])
This way, we don't really need to faff with RandomGens. I dunno if this is the most ideal solution, so cause I am a bit of a noob at this, please let me know if there is a better way of doing this.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | m1531 |
