[Haskell-cafe] Right way to implement setPixel function

Job Vranish jvranish at gmail.com
Thu Aug 20 13:05:22 EDT 2009


Your setPixel function is almost ready to work in a State monad
If you modify your setPixel function slightly like so:

setPixel' :: Int -> Int -> Color -> B.ByteString -> ((), B.ByteString)
setPixel'  x y (r,g,b) image = ((), B.concat [beforePixel, pixel,
afterPixel])

and then wrap it in the State monad constructor:

setPixel = State setPixel'

then you can do

drawPixels = do
  setPixel 5 10 (200, 0, 0)
  setPixel 20 1 (0, 200, 0)
  setPixel 90 2 (0, 0, 200)

modifiedImage = execState drawPixels originalImage

See! you were already using a monad and didn't even know it! :D

Performance wise,  B.concat is O(n), which is very not good for your
purpose. It copies the whole string and the optimizer won't be able to
magically make it go away. For something that works in O(1), you will have
to use something like STArrays instead of bytestrings.

- Job



On Thu, Aug 20, 2009 at 2:32 AM, CK Kashyap <ck_kashyap at yahoo.com> wrote:

> Hi,
> I had posted a note on line drawing algo with Haskell some time back. Now,
> I am trying to write a PNM image.
>
> import qualified Data.ByteString as B
>
> width = 256
> height = 256
> bytesInImage = width * height * 3
> blankImage =  B.pack $ take bytesInImage (repeat 0)
>
> type Color = (Int,Int,Int)
> setPixel :: B.ByteString -> Int -> Int -> Color -> B.ByteString
> setPixel image x y (r,g,b) = B.concat [beforePixel, pixel, afterPixel]
>         where
>                 beforePixel = B.take before image
>                 afterPixel = B.drop (before+3) image
>                 pixel=B.pack [(fromIntegral r),(fromIntegral
> g),(fromIntegral b)]
>                 -- number of bytes before the 3 bytes of
>                 -- the pixel at x y
>                 before = (y * width * 3) + (x * 3) - 3
>
> main = do
>         putStrLn "P6"
>         putStrLn ( (show width) ++ " " ++ (show height) )
>         putStrLn "255"
>         -- Set a red pixel at 100 100
>         B.putStr (setPixel blankImage 100 100 (255,0,0))
>
>
> Can I please have some review comments on the code above? Would recreating
> the entire ByteString for each setPixel be an overhead?
> Also, I am barely beginning to grasp the Monad concept....I was wondering
> if there could be a monadic style of implementation of this - that could
> potentially have a series of setPixels inside a do block?
>
> Regards,
> Kashyap
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20090820/34ac8254/attachment.html


More information about the Haskell-Cafe mailing list