Take the 2-minute tour ×

I have this function in Haskell (I am using the Haskell-SDL library):

pixel :: Surface -> Int16 -> Int16 -> Pixel -> IO Bool

pixel screen x y color

I want to use this to take a 2D array (or some other kind of data structure) and draw it to the screen, one pixel at a time. I looked into doing it with forM_ but can't figure out how to get it to operate on the x and y arguments.

I'm pretty new to Haskell and functional programming in general. I'm working my way through Yet Another Haskell Tutorial but this problem just has me stumped.

In case it's relevant to the solution, I'm trying to write a raytracer. It has to perform a calculation for each pixel, then write that pixel to the screen.

share|improve this question
Have you figured out yet how to represent a 2D array in Haskell? –  Gabe Feb 11 '11 at 4:49
I believe it could be done with nested lists, like so: [[1,2,3],[4,5,6],[7,8,9]] –  extropic-engine Feb 11 '11 at 4:59
Haskell has proper arrays of various kinds, using a nested list of pixels is not a good idea. Check my answer below. –  snk_kid Feb 11 '11 at 9:50

3 Answers 3

up vote 1 down vote accepted

You need to split two problems here. First you need to compute the pixel value. This should be a pure function of the scene and the coordinate of the ray you are firing into it. Then you need to write that pixel value to the screen.

So first you want a function:

type Coord = (Int, Int)

raytrace :: Scene -> Coord -> (Coord, Colour)  
    -- You will see why it returns this pair in a few lines

Then you want to call that function for every pixel in your surface, to get a list of coordinate-colour pairs:

allCoords :: Int -> Int -> [Coord]
allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]]

allPixels :: Scene -> Int -> Int -> [(Coord, Colour)]
allPixels scene w h = map (raytrace scene) (allCoords w h)

And finally put the list of pixels onto the display surface using your "pixel" function.

writeScene :: Surface -> Scene -> Int -> Int -> IO ()
writeScene surface scene w h = mapM_ writePixel (allPixels scene w h)
    where writePixel ((x,y),c) = pixel surface x y c

The only thing is, your "pixel" function returns an "IO Bool". I don't know why, so I've ignored it by using "mapM_" rather than "mapM".

This looks like it builds a horribly inefficient list of coordinate-colour pairs and then iterates through it to draw the picture. But in fact, thanks to the lazy nature of Haskell, it actually compiles down to a loop that generates each colour and then calls "pixel" on the result.

share|improve this answer

Haskell has real arrays of various kinds. To me it seems like you're doing something quite inefficient, you want to create a pixel buffer and blit it to another buffer? it would be much more efficient to create a new SDL surface (for which you can get/set pixels) and blit that to another surface/screen or create a real array of pixels and create SDL surface with that then use SDL's blit routines. If you explain what you're trying to do I think we can show you a better way.

share|improve this answer
I'm trying to write a raytracer. It has to perform a calculation for each pixel, then write that pixel to the screen. –  extropic-engine Feb 11 '11 at 14:54
@chuzzum I suggest either you read/write to the screen back buffer or create an empty SDL surface which is just a pixel buffer (for which you can manipulate pixels) and blit (blitSurface) that surface to the back buffer or create a mutable unboxed array for which you have various options such as IOUArray, STUArray, StorableArray, Unboxed.MVector (hackage.haskell.org/package/vector) then copy the pixels over to the back buffer. SDL has a function which can create an SDL surface from an array and the haskell bindings exposes this too. Using a 2D list of pixels is bad idea really. –  snk_kid Feb 11 '11 at 15:47
Is there a major performance advantage to doing so? Since the only thing I'm ever going to be doing is iterating over it, I don't see why a list is any worse or better than an array. What's the advantage of using a mutable array over immutable lists, for example? But I do think writing directly to the screen is probably the best solution. –  extropic-engine Feb 11 '11 at 15:52
There is such a thing as immutable arrays too, as well both boxed & unboxed variants. The major advantage of an unboxed array over 2D list is 1. with Unboxed arrays you have a contiguous block of memory even with multiple dimensions. 2. much better cache coherency, 2D linked-list is going to have very poor cache coherency. 3. Smaller memory consumption, lists nodes are allocated individually as well as their elements all of which are going to be scattered around in memory. 3. With some types of Haskell array you can just pass a pointer of an array to C binding libraries with no overhead and... –  snk_kid Feb 11 '11 at 16:46
4. Even iterating over a list is going to be slightly slower than an array but this is going to be an insignificant difference. 5. Indexing O(1) as long as you know all the indices of the multi-dimensional array. Isn't indexing in to a 2D list going to be a O(N^2) operation? I'm not saying you should avoid lists ever just that they are not appropriate in some cases and this case, the case of represnenting a pixel buffer I wouldn't consider 2D List a good idea when you have arrays. –  snk_kid Feb 11 '11 at 16:52

If you are using nested lists, do:

import Control.Monad
plot :: Surface -> [[Pixel]] -> IO ()
plot surf = zipWithM_ (\ y -> zipWithM_ (\ x c -> pixel surf x y c) [0..]) [0..]
share|improve this answer

Your Answer


