[Haskell-beginners] IO ( stuff )

Paul Monday paul.monday at parsci.com
Mon Dec 12 18:16:37 CET 2011


Thank you SO much for the discussion.  I've learned quite a bit over the course of it.  As one would expect, lifting wasn't my only issue … I had some rather annoying Unbox / Boxed / [] problems with the recursion.

I stepped way back finally this morning to think about the problem and the discussion points.  

I was able to make use of laziness with the randomRs function.  randomRs is nice since there are no side-effects, I get an "infinite" list of random numbers that can easily be broken into rows and matrices lazily.

So, here is how I generated two square matrices with rows and columns = n (some other artifacts are included here as well, like the Matrix type I'm using)

data Matrix a = Matrix (V.Vector (U.Vector a))
    deriving (Show, Eq)

makematrix :: [Float] -> Int -> Int -> [U.Vector Float]
makematrix xs n 0 = []
makematrix xs n r = (U.fromList $ ys) : makematrix zs n (r - 1)
    where (ys, zs) = splitAt n xs

main :: IO ()
main = do
    args <- getArgs
    let n = read (args !! 0) :: Int
    let minrange = read (args !! 1) :: Float
    let maxrange = read (args !! 2) :: Float
    let s = read (args !! 3) :: Int
    let g = mkStdGen s
    let range = (minrange, maxrange)
    let all = randomRs range g
    
    let ma = Matrix $ (V.fromList (makematrix all n n))
    let mb = Matrix $ (V.fromList (makematrix (drop (n*n) all)  n n))

    ...

As with all Haskell I'm learning, I'm 100% sure there are quite a few better ways to write this ;-)

Still, again, I can't thank you enough for the thoughtful discussion on IO and randomness.  I have avoided running back to Java with my tail between my legs for another day.

Paul Monday
Parallel Scientific, LLC.
paul.monday at parsci.com




On Dec 9, 2011, at 3:05 PM, David McBride wrote:

> I wish I'd known this when I was first beginning, but it is possible
> to do randomness outside of IO, surprisingly easily.  I like to use
> the monadRandom library, which provides some monads and monad
> transformers for this task.  I too became frustrated when I wrote a
> roguelike but could not figure out how to inject randomness into it
> when I wanted.  A program you would write might be like this:
> 
> data Obstacle = Mon (Int, Int) Monster | Door (Int, Int) | Trap (Int,
> Int) deriving (Show, Enum)
> data Monster = Orc | Wolf | Dragon deriving (Show, Enum)
> 
> main = do
>  print =<< evalRandIO randomObstacle
> 
> randomObstacle :: RandomGen g => Rand g Obstacle
> randomObstacle = do
>  x <- getRandomR (0,2::Int)
>  case x of
>    0 -> Mon <$> randomLocation <*> randomMonster
>    1 -> Door <$> randomLocation
>    2 -> Trap <$> randomLocation
> 
> randomLocation :: RandomGen g => Rand g (Int,Int)
> randomLocation = do
>  x <- getRandomR (0,10)
>  y <- getRandomR (0,10)
>  return (x,y)
> 
> randomMonster :: RandomGen g => Rand g Monster
> randomMonster = do
>  x <- getRandomR (0,2::Int)
>  return $ case x of
>    0 -> Orc
>    1 -> Dragon
>    2 -> Wolf
> 
> This way, even though my randomBlah functions do not have IO in them,
> nor do they pass around a stdGen around, but they can be combined
> willy nilly as needed, and only computed when you want them to.  I
> also could have made Random instances for Obstacle and Monster so that
> I did not have to do the cases in the code, making things easier to
> understand.
> 
> On Fri, Dec 9, 2011 at 3:27 PM, Brent Yorgey <byorgey at seas.upenn.edu> wrote:
>>> Does "impurity" from something
>>> like a random number generator or file I/O have to move it's way all
>>> the way through my code?
>> 
>> No, only through the parts that actually have to do file I/O or
>> generate random numbers or whatever.  However, cleanly separating the
>> IO code from the non-IO/"pure" code takes some experience.  It does
>> seem to be a common experience of people learning Haskell that IO ends
>> up "infecting" everything, even stuff that shouldn't have to do any
>> IO, but with good design this is not necessary.
>> 
>> In your particular case, your matrix generation function does depend
>> on random number generation so it makes sense that its type must
>> involve IO. However, if you go on to write other functions which do
>> deterministic operations on matrices, their types should *not* involve
>> IO, even if you pass randomly generated matrices to them as
>> arguments.
>> 
>> -Brent
>> 
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://www.haskell.org/mailman/listinfo/beginners
> 
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners




More information about the Beginners mailing list