[Haskell-cafe] Bit streams programs in Haskell

Chris Kuklewicz haskell at list.mightyreason.com
Wed Mar 22 19:14:49 EST 2006


Per Gustafsson wrote:
>
> Haskell gurus,
>

I am not a guru, but I'll clean up some of this.

> Our experience in writing efficient (and beautiful) Haskell programs is
> close to (if not below) zero. Also, perhaps our mind might be suffering
> from severe case of strictness and might be completely unable to `think
> lazily'. So, we request your help in noticing obvious NO-NOs and stupid
> mistakes that we might have made. We even welcome completely different
> Haskell programs provided they adhere to the constraint mentioned
> above -- no mutation.
>
> Best regards,
>
> Kostis Sagonas and Per Gustafsson
>

I can't test this, but I have attached a new version of huffman.hs that may
perform a bit better.  I don't know if all the changes I made helped instead of
hurt.  I doubt it was sped up by much.

-- 
Chris Kuklewicz
-------------- next part --------------
--module Huffman where
import System.IO
import Data.Bits
import Data.Word
import Data.Array.IO
import Data.Array.Unboxed hiding ((!))
import Data.Array.Base(unsafeAt)
import System(getArgs)
import System.CPUTime(getCPUTime)
import Foreign.Marshal.Array (withArrayLen)
import Control.Exception(bracket)

data HuffTree  = Leaf Word8 | Branch HuffTree HuffTree 

type A = UArray Int Word8

(!) = unsafeAt

iter = 10

{-- the do_iter function repeats a function iter times
 it is not pretty, but it is hard to convince haskell to 
 repeat a computation many times --}

do_iter 1 func input = let x = func input
                       in return x
do_iter k func input =  let x = func input
                        in seq (last x) (do_iter (k-1) func input)

main =
    do 
     [arg] <- getArgs
     handle <- openFile arg ReadMode
     let size = 2000000
     arrM <- newArray (0,pred size) 0 :: IO (IOUArray Int Word8)
     read_size <- hGetArray handle arrM size
     -- convert to immutable array
     arr <- unsafeFreeze arrM :: IO (UArray Int Word8)
     t0 <- getCPUTime
     res <- do_iter iter huff arr
     t1 <- getCPUTime
     putStr ((show ((fromInteger(t1-t0)::Float)/(1000000000000.0::Float))))
     bracket (openBinaryFile (arg++".haskell") WriteMode)
             hClose
             (\file -> withArrayLen res (flip (hPutBuf file)))

huff:: A -> [Word8]
huff arr  = let (hufftree, newindex) = build_tree 4 arr 
                limit = get_32bit_int newindex arr
            in huffdecode ((newindex+4)*8) arr hufftree (limit+((newindex+4)*8))

huffdecode :: Int -> A -> HuffTree -> Int -> [Word8]
huffdecode index arr tree limit = helper index tree
  where helper index (Leaf charval) | index == limit = []
                                    | otherwise      = charval : helper index tree 
        helper index (Branch left right) | index `seq` True = 
            helper (index+1) (if get_bit arr index then right else left)

get_bit :: A -> Int -> Bool
{-# INLINE get_bit #-}
get_bit arr bitoffset =
    let byte = arr ! (shiftR bitoffset 3)
    in testBit (shiftL byte (bitoffset .&. 7)) 7

build_tree :: Int->A->(HuffTree,Int)
build_tree index arr =
    let size = get_16_bitint index arr
        build_tree_2 index limit
            | (limit-index) == 1 = Leaf (arr ! index)
            | otherwise          = let left_size = get_16_bitint index arr
                                   in Branch (build_tree_2 (index+2)           (index+2+left_size))
                                             (build_tree_2 (index+4+left_size) limit              )
    in (build_tree_2 (index+2) (index+2+size)
       ,(index+2+size))

get_16_bitint :: Int -> A -> Int
{-# INLINE get_16_bitint #-}
get_16_bitint index arr =
    (shiftL (fromIntegral (arr ! index)) 8) .|. 
    (fromIntegral (arr ! (index+1)))

get_32bit_int :: Int -> A -> Int
{-# INLINE get_32bit_int #-}
get_32bit_int index arr =
    (shiftL (fromIntegral (arr ! index)) 24) .|. 
    (shiftL (fromIntegral (arr ! (index+1))) 16) .|.
    (shiftL (fromIntegral (arr ! (index+2))) 8) .|. 
    (fromIntegral (arr ! (index+3)))     


More information about the Haskell-Cafe mailing list