The functional equivalent of iterating over a two-dimensional array

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

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

pixel screen xy color

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

I am new to Haskell and functional programming in general. I am working on another Haskell tutorial, but this problem just puzzled me.

In case this relates to a solution, I am trying to write a raytracer. He must perform the calculation for each pixel, and then write this pixel to the screen.

+6
functional-programming haskell
source share
3 answers

Here you need to separate the two problems. First you need to calculate the pixel value. This should be a pure function of the scene and the coordinates of the beam you are shooting at. Then you need to write this value to the screen.

So first you need 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 this function for each pixel on your surface to get a list of coordinate pairs:

 allCoords :: Int -> Int -> [Coord] allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]] allPixels :: Scene -> Int -> Int -> [(Coord, Colour)] allPixels scene wh = map (raytrace scene) (allCoords wh) 

Finally, place the list of pixels on the display surface using the pixel function.

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

The only thing your pixel function returns is โ€œIO Boolโ€. I donโ€™t know why, so I ignored it using "mapM_" and not "mapM".

It looks like it creates a terribly inefficient list of coordinate pairs and colors, and then iterates to draw an image. But actually, thanks to the lazy nature of Haskell, it actually comes down to a loop that generates each color and then calls a โ€œpixelโ€ on the result.

+1
source share

If you use nested lists, follow these steps:

 import Control.Monad plot :: Surface -> [[Pixel]] -> IO () plot surf = zipWithM_ (\ y -> zipWithM_ (\ xc -> pixel surf xyc) [0..]) [0..] 
+3
source share

Haskell has real arrays of various types. It seems to me that you are doing something rather inefficient, do you want to create a pixel buffer and split it into another buffer? it would be much more efficient to create a new SDL surface (for which you can get / set pixels) and add it to another surface / screen or create a real array of pixels and create an SDL surface with that, and then use the SDL blit routines. If you explain what you are trying to do, I think we can show you the best way.

+2
source share

All Articles