[Haskell-cafe] wc again (Lists and type classes)
MR K P SCHUPKE
k.schupke at imperial.ac.uk
Fri Oct 15 06:03:30 EDT 2004
Have been playing with the idea of a list class like
the one I posted earlier... but now a bit streamlined.
I have implemented wc using this class and a nice buffer
list. The result is something 4 times slower than the
current language-shootout code, but is rather neater.
The restriction on getting the full speed of the current code
is the requirement to freeze the IOUArray to get it out of the
IO monad. This could be solved with an "IOList" type but this
would not be compatible with the types for a 'normal' list.
Here's the code for wc:
--------------------------------------------------------------
main :: IO ()
main = do
l <- hGetIList 4096 stdin
print $ wc l ' ' 0 0 0
wc :: List l Word8 => l Word8 -> Char -> Int -> Int -> Int -> (Int,Int,Int)
wc l p i j k
| p `seq` i `seq` j `seq` k `seq` False = undefined
| not $ Main.null l, h <- (toEnum . fromEnum . Main.head) l, t <- Main.tail l = case isSpace h of
False -> wc t h (i + 1) (j + if isSpace p then 1 else 0) k
_ -> wc t h (i + 1) j (k + if h == '\n' then 1 else 0)
| otherwise = (i,j,k)
---------------------------------------------------------------
And here's the definition of the list class and instances
(one is provided for a normal list for reference)
--------------------------------------------------------------
{-# OPTIONS -fglasgow-exts #-}
{-# OPTIONS -fallow-undecidable-instances #-}
module Main where
import Char
import GHC.IOBase
import System.IO
import Data.Word
import Data.Array.IO
import Data.Array.Unboxed
data IList a i e = ICons i i (a i e) (IList a i e) | INil
class List l e where
nil :: l e
null :: l e -> Bool
head :: l e -> e
tail :: l e -> l e
(+:) :: e -> l e -> l e
class List (l a i) e => ListPlus l a i e where
(++:) :: a i e -> l a i e -> l a i e
part :: a i e -> i -> l a i e -> l a i e
infixr 9 +:
infixr 9 ++:
instance List [] e where
nil = []
null (_:_) = False
null _ = True
head (a:_) = a
tail (_:l) = l
a +: l = a:l
instance (IArray a e,Ix i,Num i) => List (IList a i) e where
nil = INil
null INil = True
null _ = False
head (ICons i _ a _) = a!i
head _ = error "head: empty list"
tail (ICons i j a l)
| i < j = ICons (i+1) j a l
| otherwise = l
tail _ = error "tail: empty list"
a +: l = ICons 0 0 (array (0,0) [(0,a)]) l
instance (IArray a e,Ix i,Num i) => ListPlus IList a i e where
a ++: l
| e >= s = ICons s e a l
| otherwise = l
where ~(s,e) = bounds a
part a i l
| e >= i = ICons s i a l
| otherwise = l
where ~(s,e) = bounds a
hGetIList :: Int -> Handle -> IO (IList UArray Int Word8)
hGetIList bufSize h = do
mt <- newArray_ (0,bufSize-1)
ioLoop mt
where
ioLoop mt = unsafeInterleaveIO $ do
sz <- hGetArray h mt bufSize
hd <- freeze mt
case sz of
0 -> return nil
n | n < bufSize -> do
return (part hd (n-1) nil)
| otherwise -> do
tl <- ioLoop mt
return (hd ++: tl)
--------------------------------------------------------------------------
Keean.
More information about the Haskell-Cafe
mailing list