user1851482
user1851482

Reputation: 11

Plotting a Random walk in Haskell

Im trying to plot a random walk in haskell. Im useing getStdGen for the random nummbers. Im useing Chart.Easy for the plotting. Im a pleb at haskell and I cant understand the compiler error Im getting.

import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo
import System.Random

main = toFile def "random_walk.png" $ do
 layout_title .= "Random Walk"
 setColors [opaque blue, opaque red]
 g <- getStdGen
 plot (line "random walk" [ take 100 $ walk (0,0) ( randoms g :: [Float])])

walk :: (Float, Float) -> [Float] -> [(Float, Float)]
walk (x,y) (dx:dy:list) = (x+dx,y+dy):(walk (x+dx,y+dy) list)

The error is:

[1 of 1] Compiling Main             ( simple.hs, interpreted )

simple.hs:8:7: error:
    * Couldn't match type `IO'
                     with `Control.Monad.Trans.State.Lazy.StateT
                             (Layout Float Float) (Control.Monad.Trans.State.Lazy.State CState)'
      Expected type: Control.Monad.Trans.State.Lazy.StateT
                       (Layout Float Float)
                       (Control.Monad.Trans.State.Lazy.State CState)
                       StdGen
        Actual type: IO StdGen
    * In a stmt of a 'do' block: g <- getStdGen
      In the second argument of `($)', namely
        `do layout_title .= "Random Walk"
            setColors [opaque blue, opaque red]
            g <- getStdGen
            plot
              (line
                 "random walk" [take 100 $ walk (0, 0) (randoms g :: [Float])])'
      In the expression:
        toFile def "random_walk.png"
          $ do layout_title .= "Random Walk"
               setColors [opaque blue, opaque red]
               g <- getStdGen
               plot
                 (line
                    "random walk" [take 100 $ walk (0, 0) (randoms g :: [Float])])
  |
8 |  g <- getStdGen
  |       ^^^^^^^^^
Failed, no modules loaded.

Dose anyone understand? Can anyone help me? Any other comments?

After code was fixed, the reslut was this image.

Upvotes: 0

Views: 228

Answers (1)

K. A. Buhr
K. A. Buhr

Reputation: 51129

The problem is that toFile's third argument is an action in a special EC monad. This monad can't do IO, so you can't include IO actions like getStdGen in its do-block.

Instead, use a separate outer IO do-block to get the random number stream you need as a pure value, and then you can freely use it in the inner EC do-block, like so:

main :: IO ()
main = do
  -- this is do-block for the IO monad
  nums <- randomRs (-1,1) <$> getStdGen
  toFile def "random_walk.png" $ do
    -- this is the do-block for the EC monad
    layout_title .= "Random Walk"
    setColors [opaque blue, opaque red]
    plot (line "random walk" [ take 100 $ walk (0,0) nums ])

walk :: (Float, Float) -> [Float] -> [(Float, Float)]
walk (x,y) (dx:dy:list) = (x+dx,y+dy):(walk (x+dx,y+dy) list)

Upvotes: 3

Related Questions