Thoughts on Bresenham's Algorithm in Haskell

I'm still hacking away at little bits of Haskell, gradually learning my way around.

I happened to find code for Bresenham's Algorithm on Rosetta Code. It made me uncomfortable - it looked like the author had pushed a C-shaped programme into Haskell-shaped syntax.

This was just my first impression - I don't know the language well enough to know when to use the State Monad - and I'm certainly not qualified to criticise the orginal author of the following code.

module Bitmap.Line(line) where
-- code from the Rosetta Code project
 
import Bitmap
import Control.Monad
import Control.Monad.ST
import qualified Data.STRef
 
var = Data.STRef.newSTRef
get = Data.STRef.readSTRef
mutate = Data.STRef.modifySTRef
 
line :: Color c => Image s c -> Pixel -> Pixel -> c -> ST s ()
line i (Pixel (xa, ya)) (Pixel (xb, yb)) c = do
    yV <- var y1
    errorV <- var $ deltax `div` 2
    forM_ [x1 .. x2] (\x -> do
        y <- get yV
        setPix i (Pixel $ if steep then (y, x) else (x, y)) c
        mutate errorV $ subtract deltay
        error <- get errorV
        when (error < 0) (do
            mutate yV (+ ystep)
            mutate errorV (+ deltax)))
  where steep = abs (yb - ya) > abs (xb - xa)
        (xa', ya', xb', yb') = if steep
          then (ya, xa, yb, xb)
          else (xa, ya, xb, yb)
        (x1, y1, x2, y2) = if xa' > xb'
          then (xb', yb', xa', ya')
          else (xa', ya', xb', yb')
        deltax = x2 - x1
        deltay = abs $ y2 - y1
        ystep = if y1 < y2 then 1 else -1

I'm still a beginner at Haskell, but would a solution along the following lines be more idiomatic? Would it be less efficient?

module Line(line) where
 
line :: (Int, Int) -> Int -> [(Int, Int)]
line (x, y) inv_grad = line' (x, y) inv_grad (inv_grad `div` 2)
 
line' :: (Int, Int) -> Int -> Int -> [(Int, Int)]
line' (x, y) inv_grad 0 =     (x, y) : line' (x+1, y+1) inv_grad (inv_grad-1)
line' (x, y) inv_grad err_y = (x, y) : line' (x+1, y) inv_grad (err_y-1)

Note: this code is not functionally equivalent, just a proof of concept. It can only produce lists of points in the first octant. inv_gradient is one divided by the line's gradient.

*Line> :load bresenham
[1 of 1] Compiling Line             ( bresenham.hs, interpreted )
Ok, modules loaded: Line.
*Line> take 10 $ line (0, 0) 3
[(0,0),(1,0),(2,1),(3,1),(4,1),(5,2),(6,2),(7,2),(8,3),(9,3)]

Please post comments either below, or on Reddit.

Comments

Tiffany & Co Shop specialises

Tiffany & Co Shop specialises in superior sterling silver Tiffany Jewelry, Tiffany Shop provides hundreds of discount and fashion Tiffany Jewellery,
tiffany jewellery
tiffany co
tiffany
GHD Styler Hair Straightener - shop online for ghd stylers, the new limited edition purple ghd IV styler & gift set, ghd hair care products,
cheap ghd
ghd straighteners
ghd pink
ghd
ghd Hair Straighteners
the women like ugg boots,ugg cardy boots,you could buy cheap ugg boots from here!
ugg boots
uggs

Abercrombie

High Waist Straight-leg pants outfit stunted jacket, showing slender eye-catching position, pertinent mixture of units Cheap Abercrombie and Fitch Outerwears Cheap Abercrombie and Fitch Outerwears discount Abercrombie and Fitch Outerwears discount Abercrombie and Fitch Outerwears Abercrombie and Fitch Outerwears sale Abercrombie and Fitch Outerwears sale buy Abercrombie and Fitch Outerwears buy Abercrombie and Fitch Outerwears Cheap Abercrombie Fitch Outerwears Cheap Abercrombie Fitch Outerwears discount Abercrombie Fitch Outerwears discount Abercrombie Fitch Outerwears Abercrombie Fitch Outerwears sale Abercrombie Fitch Outerwears sale buy Abercrombie Fitch Outerwears buy Abercrombie Fitch Outerwears Cheap Abercrombie Outerwears Cheap Abercrombie Outerwears discount Abercrombie Outerwears discount Abercrombie Outerwears Abercrombie Outerwears sale Abercrombie Outerwears sale buy Abercrombie Outerwears at Break; DSquared jeans on The patches, holes, stains a Less.