diff --git a/Data/ByteString.hs b/Data/ByteString.hs
--- a/Data/ByteString.hs
+++ b/Data/ByteString.hs
@@ -1,4 +1,5 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -XMagicHash -XUnboxedTuples #-}
 
 -- #prune
 
@@ -7,8 +8,8 @@
 -- Copyright   : (c) The University of Glasgow 2001,
 --               (c) David Roundy 2003-2005,
 --               (c) Simon Marlow 2005
---               (c) Don Stewart 2005-2006
 --               (c) Bjorn Bringert 2006
+--               (c) Don Stewart 2005-2008
 --
 --               Array fusion code:
 --               (c) 2001,2002 Manuel M T Chakravarty & Gabriele Keller
@@ -96,7 +97,6 @@
         -- ** Accumulating maps
         mapAccumL,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)
         mapAccumR,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)
-        mapIndexed,             -- :: (Int -> Word8 -> Word8) -> ByteString -> ByteString
 
         -- ** Generating and unfolding ByteStrings
         replicate,              -- :: Int -> Word8 -> ByteString
@@ -128,9 +128,9 @@
         isPrefixOf,             -- :: ByteString -> ByteString -> Bool
         isSuffixOf,             -- :: ByteString -> ByteString -> Bool
         isInfixOf,              -- :: ByteString -> ByteString -> Bool
-        isSubstringOf,          -- :: ByteString -> ByteString -> Bool
 
         -- ** Search for arbitrary substrings
+        breakSubstring,         -- :: ByteString -> ByteString -> (ByteString,ByteString)
         findSubstring,          -- :: ByteString -> ByteString -> Maybe Int
         findSubstrings,         -- :: ByteString -> ByteString -> [Int]
 
@@ -187,7 +187,6 @@
         readFile,               -- :: FilePath -> IO ByteString
         writeFile,              -- :: FilePath -> ByteString -> IO ()
         appendFile,             -- :: FilePath -> ByteString -> IO ()
---      mmapFile,               -- :: FilePath -> IO ByteString
 
         -- ** I\/O with Handles
         hGetLine,               -- :: Handle -> IO ByteString
@@ -198,8 +197,7 @@
         hPutStr,                -- :: Handle -> ByteString -> IO ()
         hPutStrLn,              -- :: Handle -> ByteString -> IO ()
 
-        -- undocumented deprecated things:
-        join                    -- :: ByteString -> [ByteString] -> ByteString
+        breakByte
 
   ) where
 
@@ -216,14 +214,11 @@
 
 import Data.ByteString.Internal
 import Data.ByteString.Unsafe
-import Data.ByteString.Fusion
 
 import qualified Data.List as List
 
 import Data.Word                (Word8)
-import Data.Maybe               (listToMaybe)
-import Data.Array               (listArray)
-import qualified Data.Array as Array ((!))
+import Data.Maybe               (isJust, listToMaybe)
 
 -- Control.Exception.bracket not available in yhc or nhc
 #ifndef __NHC__
@@ -291,23 +286,17 @@
 
 -- -----------------------------------------------------------------------------
 
-instance Eq  ByteString
-    where (==)    = eq
+instance Eq  ByteString where
+    (==)    = eq
 
-instance Ord ByteString
-    where compare = compareBytes
+instance Ord ByteString where
+    compare = compareBytes
 
 instance Monoid ByteString where
     mempty  = empty
     mappend = append
     mconcat = concat
 
-{-
-instance Arbitrary PackedString where
-    arbitrary = P.pack `fmap` arbitrary
-    coarbitrary s = coarbitrary (P.unpack s)
--}
-
 -- | /O(n)/ Equality on the 'ByteString' type.
 eq :: ByteString -> ByteString -> Bool
 eq a@(PS p s l) b@(PS p' s' l')
@@ -315,12 +304,12 @@
     | p == p' && s == s' = True     -- short cut for the same string
     | otherwise          = compareBytes a b == EQ
 {-# INLINE eq #-}
+-- ^ still needed
 
 -- | /O(n)/ 'compareBytes' provides an 'Ordering' for 'ByteStrings' supporting slices. 
 compareBytes :: ByteString -> ByteString -> Ordering
 compareBytes (PS x1 s1 l1) (PS x2 s2 l2)
     | l1 == 0  && l2 == 0               = EQ  -- short cut for empty strings
-    | x1 == x2 && s1 == s2 && l1 == l2  = EQ  -- short cut for the same string
     | otherwise                         = inlinePerformIO $
         withForeignPtr x1 $ \p1 ->
         withForeignPtr x2 $ \p2 -> do
@@ -328,32 +317,32 @@
             return $! case i `compare` 0 of
                         EQ  -> l1 `compare` l2
                         x   -> x
-{-# INLINE compareBytes #-}
 
 {-
---
--- About 4x slower over 32M
---
-compareBytes :: ByteString -> ByteString -> Ordering
-compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2) = inlinePerformIO $
+
+-- Pure Haskell version
+
+compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2)
+--    | len1 == 0  && len2 == 0                     = EQ  -- short cut for empty strings
+--    | fp1 == fp2 && off1 == off2 && len1 == len2  = EQ  -- short cut for the same string
+    | otherwise                                   = inlinePerformIO $
     withForeignPtr fp1 $ \p1 ->
         withForeignPtr fp2 $ \p2 ->
             cmp (p1 `plusPtr` off1)
                 (p2 `plusPtr` off2) 0 len1 len2
 
+-- XXX todo.
 cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering
-STRICT5(cmp)
 cmp p1 p2 n len1 len2
       | n == len1 = if n == len2 then return EQ else return LT
       | n == len2 = return GT
       | otherwise = do
-          (a :: Word8) <- peekByteOff p1 n
-          (b :: Word8) <- peekByteOff p2 n
+          a <- peekByteOff p1 n :: IO Word8
+          b <- peekByteOff p2 n
           case a `compare` b of
                 EQ -> cmp p1 p2 (n+1) len1 len2
                 LT -> return LT
                 GT -> return GT
-{-# INLINE compareBytes #-}
 -}
 
 -- -----------------------------------------------------------------------------
@@ -368,8 +357,10 @@
 singleton c = unsafeCreate 1 $ \p -> poke p c
 {-# INLINE [1] singleton #-}
 
+-- Inline [1] for intercalate rule
+
 --
--- XXX The unsafePerformIO is critical!
+-- XXX The use of unsafePerformIO in allocating functions (unsafeCreate) is critical!
 --
 -- Otherwise:
 --
@@ -432,6 +423,8 @@
 {-# INLINE unpack #-}
 
 --
+-- Have unpack fuse with good list consumers
+--
 -- critical this isn't strict in the acc
 -- as it will break in the presence of list fusion. this is a known
 -- issue with seq and build/foldr rewrite rules, which rely on lazy
@@ -457,7 +450,8 @@
     loop (p `plusPtr` off) (len-1) []
 
 {-# RULES
-    "FPS unpack-list"  [1]  forall p  . unpackFoldr p (:) [] = unpackList p
+"ByteString unpack-list" [1]  forall p  .
+    unpackFoldr p (:) [] = unpackList p
  #-}
 
 #endif
@@ -578,10 +572,6 @@
     | otherwise      = unsafeCreate (2*l-1) $ \p -> withForeignPtr x $ \f ->
         c_intersperse p (f `plusPtr` s) (fromIntegral l) c
 
-{-
-intersperse c = pack . List.intersperse c . unpack
--}
-
 -- | The 'transpose' function transposes the rows and columns of its
 -- 'ByteString' argument.
 transpose :: [ByteString] -> [ByteString]
@@ -593,7 +583,9 @@
 -- | 'foldl', applied to a binary operator, a starting value (typically
 -- the left-identity of the operator), and a ByteString, reduces the
 -- ByteString using the binary operator, from left to right.
+--
 -- This function is subject to array fusion.
+--
 foldl :: (a -> Word8 -> a) -> a -> ByteString -> a
 foldl f v (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr ->
         lgo v (ptr `plusPtr` s) (ptr `plusPtr` (s+l))
@@ -605,7 +597,8 @@
 {-# INLINE foldl #-}
 
 -- | 'foldl\'' is like 'foldl', but strict in the accumulator.
--- Though actually foldl is also strict in the accumulator.
+-- However, for ByteStrings, all left folds are strict in the accumulator.
+--
 foldl' :: (a -> Word8 -> a) -> a -> ByteString -> a
 foldl' = foldl
 {-# INLINE foldl' #-}
@@ -750,11 +743,19 @@
 -- passing an accumulating parameter from left to right, and returning a
 -- final value of this accumulator together with the new list.
 mapAccumL :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)
-#if !defined(LOOPU_FUSION)
-mapAccumL f z = unSP . loopUp (mapAccumEFL f) z
-#else
-mapAccumL f z = unSP . loopU (mapAccumEFL f) z
-#endif
+mapAccumL f acc (PS fp o len) = inlinePerformIO $ withForeignPtr fp $ \a -> do
+    gp   <- mallocByteString len
+    acc' <- withForeignPtr gp $ \p -> mapAccumL_ acc 0 (a `plusPtr` o) p
+    return $! (acc', PS gp 0 len)
+  where
+    STRICT4(mapAccumL_)
+    mapAccumL_ s n p1 p2
+       | n >= len = return s
+       | otherwise = do
+            x <- peekByteOff p1 n
+            let (s', y) = f s x
+            pokeByteOff p2 n y
+            mapAccumL_ s' (n+1) p1 p2
 {-# INLINE mapAccumL #-}
 
 -- | The 'mapAccumR' function behaves like a combination of 'map' and
@@ -762,14 +763,21 @@
 -- passing an accumulating parameter from right to left, and returning a
 -- final value of this accumulator together with the new ByteString.
 mapAccumR :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)
-mapAccumR f z = unSP . loopDown (mapAccumEFL f) z
+mapAccumR f acc (PS fp o len) = inlinePerformIO $ withForeignPtr fp $ \a -> do
+    gp   <- mallocByteString len
+    acc' <- withForeignPtr gp $ \p -> mapAccumR_ acc (len-1) (a `plusPtr` o) p
+    return $! (acc', PS gp 0 len)
+  where
+    STRICT4(mapAccumR_)
+    mapAccumR_ s n p q
+       | n <  0    = return s
+       | otherwise = do
+            x  <- peekByteOff p n
+            let (s', y) = f s x
+            pokeByteOff q n y
+            mapAccumR_ s' (n-1) p q
 {-# INLINE mapAccumR #-}
 
--- | /O(n)/ map Word8 functions, provided with the index at each position
-mapIndexed :: (Int -> Word8 -> Word8) -> ByteString -> ByteString
-mapIndexed f = loopArr . loopUp (mapIndexEFL f) 0
-{-# INLINE mapIndexed #-}
-
 -- ---------------------------------------------------------------------
 -- Building ByteStrings
 
@@ -781,17 +789,27 @@
 -- Note that
 --
 -- > last (scanl f z xs) == foldl f z xs.
+--
 scanl :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString
-#if !defined(LOOPU_FUSION)
-scanl f z ps = loopArr . loopUp (scanEFL f) z $ (ps `snoc` 0)
-#else
-scanl f z ps = loopArr . loopU (scanEFL f) z $ (ps `snoc` 0)
-#endif
 
+scanl f v (PS fp s len) = inlinePerformIO $ withForeignPtr fp $ \a ->
+    create (len+1) $ \q -> do
+        poke q v
+        scanl_ v 0 (a `plusPtr` s) (q `plusPtr` 1)
+  where
+    STRICT4(scanl_)
+    scanl_ z n p q
+        | n >= len  = return ()
+        | otherwise = do
+            x <- peekByteOff p n
+            let z' = f z x
+            pokeByteOff q n z'
+            scanl_ z' (n+1) p q
+{-# INLINE scanl #-}
+
     -- n.b. haskell's List scan returns a list one bigger than the
     -- input, so we need to snoc here to get some extra space, however,
     -- it breaks map/up fusion (i.e. scanl . map no longer fuses)
-{-# INLINE scanl #-}
 
 -- | 'scanl1' is a variant of 'scanl' that has no starting value argument.
 -- This function will fuse.
@@ -805,7 +823,19 @@
 
 -- | scanr is the right-to-left dual of scanl.
 scanr :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString
-scanr f z ps = loopArr . loopDown (scanEFL (flip f)) z $ (0 `cons` ps) -- extra space
+scanr f v (PS fp s len) = inlinePerformIO $ withForeignPtr fp $ \a ->
+    create (len+1) $ \q -> do
+        poke (q `plusPtr` len) v
+        scanr_ v (len-1) (a `plusPtr` s) q
+  where
+    STRICT4(scanr_)
+    scanr_ z n p q
+        | n <  0    = return ()
+        | otherwise = do
+            x <- peekByteOff p n
+            let z' = f x z
+            pokeByteOff q n z'
+            scanr_ z' (n-1) p q
 {-# INLINE scanr #-}
 
 -- | 'scanr1' is a variant of 'scanr' that has no starting value argument.
@@ -917,19 +947,28 @@
 -- instead of findIndexOrEnd, we could use memchr here.
 
 -- | 'break' @p@ is equivalent to @'span' ('not' . p)@.
+--
+-- Under GHC, a rewrite rule will transform break (==) into a
+-- call to the specialised breakByte:
+--
+-- > break ((==) x) = breakByte x
+-- > break (==x) = breakByte x
+--
 break :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
 break p ps = case findIndexOrEnd p ps of n -> (unsafeTake n ps, unsafeDrop n ps)
 #if __GLASGOW_HASKELL__ 
 {-# INLINE [1] break #-}
+#endif
 
 {-# RULES
-"FPS specialise break (x==)" forall x.
+"ByteString specialise break (x==)" forall x.
     break ((==) x) = breakByte x
-"FPS specialise break (==x)" forall x.
+"ByteString specialise break (==x)" forall x.
     break (==x) = breakByte x
   #-}
-#endif
 
+-- INTERNAL:
+
 -- | 'breakByte' breaks its ByteString argument at the first occurence
 -- of the specified byte. It is more efficient than 'break' as it is
 -- implemented with @memchr(3)@. I.e.
@@ -975,9 +1014,9 @@
 {-# INLINE spanByte #-}
 
 {-# RULES
-"FPS specialise span (x==)" forall x.
+"ByteString specialise span (x==)" forall x.
     span ((==) x) = spanByte x
-"FPS specialise span (==x)" forall x.
+"ByteString specialise span (==x)" forall x.
     span (==x) = spanByte x
   #-}
 
@@ -1021,7 +1060,6 @@
                   -> IO [ByteString]
 
         splitLoop pred' p idx' off' len' fp'
-            | pred' `seq` p `seq` idx' `seq` off' `seq` len' `seq` fp' `seq` False = undefined
             | idx' >= len'  = return [PS fp' off' idx']
             | otherwise = do
                 w <- peekElemOff p (off'+idx')
@@ -1088,7 +1126,6 @@
 
         STRICT5(splitLoop)
         splitLoop p idx' off' len' fp'
-            | p `seq` idx' `seq` off' `seq` len' `seq` fp' `seq` False = undefined
             | idx' >= len'  = return [PS fp' off' idx']
             | otherwise = do
                 (W8# x#) <- peekElemOff p (off'+idx')
@@ -1141,12 +1178,8 @@
 intercalate s = concat . (List.intersperse s)
 {-# INLINE [1] intercalate #-}
 
-join :: ByteString -> [ByteString] -> ByteString
-join = intercalate
-{-# DEPRECATED join "use intercalate" #-}
-
 {-# RULES
-"FPS specialise intercalate c -> intercalateByte" forall c s1 s2 .
+"ByteString specialise intercalate c -> intercalateByte" forall c s1 s2 .
     intercalate (singleton c) (s1 : s2 : []) = intercalateWithByte c s1 s2
   #-}
 
@@ -1315,10 +1348,9 @@
                         if k w
                             then poke t w >> go (f `plusPtr` 1) (t `plusPtr` 1) end
                             else             go (f `plusPtr` 1) t               end
-#if __GLASGOW_HASKELL__
-{-# INLINE [1] filter #-}
-#endif
+{-# INLINE filter #-}
 
+{-
 --
 -- | /O(n)/ A first order equivalent of /filter . (==)/, for the common
 -- case of filtering a single byte. It is more efficient to use
@@ -1334,14 +1366,12 @@
 {-# INLINE filterByte #-}
 
 {-# RULES
-  "FPS specialise filter (== x)" forall x.
-      filter ((==) x) = filterByte x
-  #-}
-
-{-# RULES
-  "FPS specialise filter (== x)" forall x.
-     filter (== x) = filterByte x
+"ByteString specialise filter (== x)" forall x.
+    filter ((==) x) = filterByte x
+"ByteString specialise filter (== x)" forall x.
+    filter (== x) = filterByte x
   #-}
+-}
 
 -- | /O(n)/ The 'find' function takes a predicate and a ByteString,
 -- and returns the first element in matching the predicate, or 'Nothing'
@@ -1407,34 +1437,95 @@
             i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2 `plusPtr` (l2 - l1)) (fromIntegral l1)
             return $! i == 0
 
--- | Alias of 'isSubstringOf'
+-- | Check whether one string is a substring of another. @isInfixOf
+-- p s@ is equivalent to @not (null (findSubstrings p s))@.
 isInfixOf :: ByteString -> ByteString -> Bool
-isInfixOf = isSubstringOf
+isInfixOf p s = isJust (findSubstring p s)
 
--- | Check whether one string is a substring of another. @isSubstringOf
--- p s@ is equivalent to @not (null (findSubstrings p s))@.
-isSubstringOf :: ByteString -- ^ String to search for.
-              -> ByteString -- ^ String to search in.
-              -> Bool
-isSubstringOf p s = not $ P.null $ findSubstrings p s
+-- | Break a string on a substring, returning a pair of the part of the
+-- string prior to the match, and the rest of the string.
+--
+-- The following relationships hold:
+--
+-- > break (== c) l == breakSubstring (singleton c) l
+--
+-- and:
+--
+-- > findSubstring s l ==
+-- >    if null s then Just 0
+-- >              else case breakSubstring s l of
+-- >                       (x,y) | null y    -> Nothing
+-- >                             | otherwise -> Just (length x)
+--
+-- For example, to tokenise a string, dropping delimiters:
+--
+-- > tokenise x y = h : if null t then [] else tokenise x (drop (length x) t)
+-- >     where (h,t) = breakSubstring x y
+--
+-- To skip to the first occurence of a string:
+-- 
+-- > snd (breakSubstring x y) 
+--
+-- To take the parts of a string before a delimiter:
+--
+-- > fst (breakSubstring x y) 
+--
+breakSubstring :: ByteString -- ^ String to search for
+               -> ByteString -- ^ String to search in
+               -> (ByteString,ByteString) -- ^ Head and tail of string broken at substring
 
-{-# DEPRECATED findSubstring "Do not use. The ByteString searching api is about to be replaced." #-}
+breakSubstring pat src = search 0 src
+  where
+    STRICT2(search)
+    search n s
+        | null s             = (src,empty)      -- not found
+        | pat `isPrefixOf` s = (take n src,s)
+        | otherwise          = search (n+1) (unsafeTail s)
+
 -- | Get the first index of a substring in another string,
 --   or 'Nothing' if the string is not found.
 --   @findSubstring p s@ is equivalent to @listToMaybe (findSubstrings p s)@.
 findSubstring :: ByteString -- ^ String to search for.
               -> ByteString -- ^ String to seach in.
               -> Maybe Int
-findSubstring = (listToMaybe .) . findSubstrings
+findSubstring f i = listToMaybe (findSubstrings f i)
 
-{-# DEPRECATED findSubstrings "Do not use. The ByteString searching api is about to be replaced." #-}
+{-# DEPRECATED findSubstring "findSubstring is deprecated in favour of breakSubstring." #-}
+
+{-
+findSubstring pat str = search 0 str
+    where
+        STRICT2(search)
+        search n s
+            = let x = pat `isPrefixOf` s
+              in
+                if null s
+                    then if x then Just n else Nothing
+                    else if x then Just n
+                              else     search (n+1) (unsafeTail s)
+-}
+
 -- | Find the indexes of all (possibly overlapping) occurances of a
--- substring in a string.  This function uses the Knuth-Morris-Pratt
--- string matching algorithm.
+-- substring in a string.
+--
 findSubstrings :: ByteString -- ^ String to search for.
                -> ByteString -- ^ String to seach in.
                -> [Int]
+findSubstrings pat str
+    | null pat         = [0 .. length str]
+    | otherwise        = search 0 str
+  where
+    STRICT2(search)
+    search n s
+        | null s             = []
+        | pat `isPrefixOf` s = n : search (n+1) (unsafeTail s)
+        | otherwise          =     search (n+1) (unsafeTail s)
 
+{-# DEPRECATED findSubstrings "findSubstrings is deprecated in favour of breakSubstring." #-}
+
+{-
+{- This function uses the Knuth-Morris-Pratt string matching algorithm.  -}
+
 findSubstrings pat@(PS _ _ m) str@(PS _ _ n) = search 0 0
   where
       patc x = pat `unsafeIndex` x
@@ -1453,6 +1544,7 @@
               rest = if i == n then [] else search (i+1) (next (strc i) j + 1)
       next c j | j >= 0 && (j == m || c /= patc j) = next c (kmpNext Array.! j)
                | otherwise = j
+-}
 
 -- ---------------------------------------------------------------------
 -- Zipping
@@ -1482,8 +1574,7 @@
 -- | A specialised version of zipWith for the common case of a
 -- simultaneous map over two bytestrings, to build a 3rd. Rewrite rules
 -- are used to automatically covert zipWith into zipWith' when a pack is
--- performed on the result of zipWith, but we also export it for
--- convenience.
+-- performed on the result of zipWith.
 --
 zipWith' :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> ByteString
 zipWith' f (PS fp s l) (PS fq t m) = inlinePerformIO $
@@ -1505,10 +1596,8 @@
 {-# INLINE zipWith' #-}
 
 {-# RULES
-
-"FPS specialise zipWith" forall (f :: Word8 -> Word8 -> Word8) p q .
+"ByteString specialise zipWith" forall (f :: Word8 -> Word8 -> Word8) p q .
     zipWith f p q = unpack (zipWith' f p q)
-
   #-}
 
 -- | /O(n)/ 'unzip' transforms a list of pairs of bytes into a pair of
@@ -1738,7 +1827,8 @@
 
 -- | Read a 'ByteString' directly from the specified 'Handle'.  This
 -- is far more efficient than reading the characters into a 'String'
--- and then using 'pack'.
+-- and then using 'pack'. First argument is the Handle to read from, 
+-- and the second is the number of bytes to read.
 --
 hGet :: Handle -> Int -> IO ByteString
 hGet _ 0 = return empty
diff --git a/Data/ByteString/Char8.hs b/Data/ByteString/Char8.hs
--- a/Data/ByteString/Char8.hs
+++ b/Data/ByteString/Char8.hs
@@ -1,10 +1,11 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts #-}
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -XMagicHash -XUnboxedTuples #-}
 
 -- #prune
 
 -- |
 -- Module      : Data.ByteString.Char8
--- Copyright   : (c) Don Stewart 2006
+-- Copyright   : (c) Don Stewart 2006-2008
 -- License     : BSD-style
 --
 -- Maintainer  : dons@cse.unsw.edu.au
@@ -32,6 +33,11 @@
 --
 -- > import qualified Data.ByteString.Char8 as B
 --
+-- The Char8 interface to bytestrings provides an instance of IsString
+-- for the ByteString type, enabling you to use string literals, and
+-- have them implicitly packed to ByteStrings. Use -XOverloadedStrings
+-- to enable this.
+--
 
 module Data.ByteString.Char8 (
 
@@ -92,7 +98,6 @@
         -- ** Accumulating maps
         mapAccumL,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)
         mapAccumR,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)
-        mapIndexed,             -- :: (Int -> Char -> Char) -> ByteString -> ByteString
 
         -- ** Generating and unfolding ByteStrings
         replicate,              -- :: Int -> Char -> ByteString
@@ -130,9 +135,9 @@
         isPrefixOf,             -- :: ByteString -> ByteString -> Bool
         isSuffixOf,             -- :: ByteString -> ByteString -> Bool
         isInfixOf,              -- :: ByteString -> ByteString -> Bool
-        isSubstringOf,          -- :: ByteString -> ByteString -> Bool
 
         -- ** Search for arbitrary substrings
+        breakSubstring,         -- :: ByteString -> ByteString -> (ByteString,ByteString)
         findSubstring,          -- :: ByteString -> ByteString -> Maybe Int
         findSubstrings,         -- :: ByteString -> ByteString -> [Int]
 
@@ -205,9 +210,6 @@
         hPutStr,                -- :: Handle -> ByteString -> IO ()
         hPutStrLn,              -- :: Handle -> ByteString -> IO ()
 
-        -- undocumented deprecated things:
-        join                    -- :: ByteString -> [ByteString] -> ByteString
-
   ) where
 
 import qualified Prelude as P
@@ -230,8 +232,8 @@
 import Data.ByteString (empty,null,length,tail,init,append
                        ,inits,tails,reverse,transpose
                        ,concat,take,drop,splitAt,intercalate
-                       ,sort,isPrefixOf,isSuffixOf,isInfixOf,isSubstringOf
-                       ,findSubstring,findSubstrings,copy,group
+                       ,sort,isPrefixOf,isSuffixOf,isInfixOf
+                       ,findSubstring,findSubstrings,breakSubstring,copy,group
 
                        ,getLine, getContents, putStr, putStrLn, interact
                        ,hGetContents, hGet, hPut, hPutStr, hPutStrLn
@@ -313,8 +315,8 @@
 {-# INLINE [1] pack #-}
 
 {-# RULES
-    "FPS pack/packAddress" forall s .
-       pack (unpackCString# s) = inlinePerformIO (B.unsafePackAddress s)
+"ByteString pack/packAddress" forall s .
+   pack (unpackCString# s) = inlinePerformIO (B.unsafePackAddress s)
  #-}
 
 #endif
@@ -366,10 +368,6 @@
 intersperse = B.intersperse . c2w
 {-# INLINE intersperse #-}
 
-join :: ByteString -> [ByteString] -> ByteString
-join = intercalate
-{-# DEPRECATED join "use intercalate" #-}
-
 -- | 'foldl', applied to a binary operator, a starting value (typically
 -- the left-identity of the operator), and a ByteString, reduces the
 -- ByteString using the binary operator, from left to right.
@@ -443,11 +441,6 @@
 minimum = w2c . B.minimum
 {-# INLINE minimum #-}
 
--- | /O(n)/ map Char functions, provided with the index at each position
-mapIndexed :: (Int -> Char -> Char) -> ByteString -> ByteString
-mapIndexed f = B.mapIndexed (\i c -> c2w (f i (w2c c)))
-{-# INLINE mapIndexed #-}
-
 -- | The 'mapAccumL' function behaves like a combination of 'map' and
 -- 'foldl'; it applies a function to each element of a ByteString,
 -- passing an accumulating parameter from left to right, and returning a
@@ -538,6 +531,11 @@
 {-# INLINE [1] dropWhile #-}
 #endif
 
+{-# RULES
+"ByteString specialise dropWhile isSpace -> dropSpace"
+    dropWhile isSpace = dropSpace
+  #-}
+
 -- | 'break' @p@ is equivalent to @'span' ('not' . p)@.
 break :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
 break f = B.break (f . w2c)
@@ -545,6 +543,27 @@
 {-# INLINE [1] break #-}
 #endif
 
+{-# RULES
+"ByteString specialise break (x==)" forall x.
+    break ((==) x) = breakChar x
+"ByteString specialise break (==x)" forall x.
+    break (==x) = breakChar x
+  #-}
+
+-- INTERNAL:
+
+-- | 'breakChar' breaks its ByteString argument at the first occurence
+-- of the specified char. It is more efficient than 'break' as it is
+-- implemented with @memchr(3)@. I.e.
+-- 
+-- > break (=='c') "abcd" == breakChar 'c' "abcd"
+--
+breakChar :: Char -> ByteString -> (ByteString, ByteString)
+breakChar c p = case elemIndex c p of
+    Nothing -> (p,empty)
+    Just n  -> (B.unsafeTake n p, B.unsafeDrop n p)
+{-# INLINE breakChar #-}
+
 -- | 'span' @p xs@ breaks the ByteString into two segments. It is
 -- equivalent to @('takeWhile' p xs, 'dropWhile' p xs)@
 span :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
@@ -711,13 +730,14 @@
 -- predicate.
 filter :: (Char -> Bool) -> ByteString -> ByteString
 filter f = B.filter (f . w2c)
-{-# INLINE [1] filter #-}
+{-# INLINE filter #-}
 
+{-
 -- | /O(n)/ and /O(n\/c) space/ A first order equivalent of /filter .
 -- (==)/, for the common case of filtering a single Char. It is more
 -- efficient to use /filterChar/ in this case.
 --
--- > filterByte == filter . (==)
+-- > filterChar == filter . (==)
 --
 -- filterChar is around 10x faster, and uses much less space, than its
 -- filter equivalent
@@ -727,14 +747,12 @@
 {-# INLINE filterChar #-}
 
 {-# RULES
-  "FPS specialise filter (== x)" forall x.
-      filter ((==) x) = filterChar x
-  #-}
-
-{-# RULES
-  "FPS specialise filter (== x)" forall x.
-     filter (== x) = filterChar x
+"ByteString specialise filter (== x)" forall x.
+    filter ((==) x) = filterChar x
+"ByteString specialise filter (== x)" forall x.
+    filter (== x) = filterChar x
   #-}
+-}
 
 -- | /O(n)/ The 'find' function takes a predicate and a ByteString,
 -- and returns the first element in matching the predicate, or 'Nothing'
@@ -806,8 +824,8 @@
 -- Things that depend on the encoding
 
 {-# RULES
-    "FPS specialise break -> breakSpace"
-        break isSpace = breakSpace
+"ByteString specialise break -> breakSpace"
+    break isSpace = breakSpace
   #-}
 
 -- | 'breakSpace' returns the pair of ByteStrings when the argument is
@@ -832,11 +850,6 @@
     | otherwise = do w <- peekByteOff ptr n
                      if (not . isSpaceWord8) w then firstspace ptr (n+1) m else return n
 
-{-# RULES
-    "FPS specialise dropWhile isSpace -> dropSpace"
-        dropWhile isSpace = dropSpace
-  #-}
-
 -- | 'dropSpace' efficiently returns the 'ByteString' argument with
 -- white space Chars removed from the front. It is more efficient than
 -- calling dropWhile for removing whitespace. I.e.
@@ -1001,6 +1014,9 @@
 
           combine2 b (n:m:ns) = let t = m*b + n in t `seq` (t : combine2 b ns)
           combine2 _ ns       = ns
+
+------------------------------------------------------------------------
+-- For non-binary text processing:
 
 -- | Read an entire file strictly into a 'ByteString'.  This is far more
 -- efficient than reading the characters into a 'String' and then using
diff --git a/Data/ByteString/Fusion.hs b/Data/ByteString/Fusion.hs
--- a/Data/ByteString/Fusion.hs
+++ b/Data/ByteString/Fusion.hs
@@ -1,4 +1,3 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}
 -- |
 -- Module      : Data.ByteString.Fusion
 -- License     : BSD-style
@@ -6,695 +5,17 @@
 -- Stability   : experimental
 -- Portability : portable
 --
--- Functional array fusion for ByteStrings.
+-- Stream fusion for ByteStrings.
 --
--- Originally based on code from the Data Parallel Haskell project, 
---      <http://www.cse.unsw.edu.au/~chak/project/dph>
+-- See the paper /Stream Fusion: From Lists to Streams to Nothing at All/,
+-- Coutts, Leshchinskiy and Stewart, 2007.  
 --
 
 -- #hide
 module Data.ByteString.Fusion (
 
-    -- * Fusion utilities
-    loopU, loopL, fuseEFL,
-    NoAcc(NoAcc), loopArr, loopAcc, loopSndAcc, unSP,
-    mapEFL, filterEFL, foldEFL, foldEFL', scanEFL, mapAccumEFL, mapIndexEFL,
-
-    -- ** Alternative Fusion stuff
-    -- | This replaces 'loopU' with 'loopUp'
-    -- and adds several further special cases of loops.
-    loopUp, loopDown, loopNoAcc, loopMap, loopFilter,
-    loopWrapper, sequenceLoops,
-    doUpLoop, doDownLoop, doNoAccLoop, doMapLoop, doFilterLoop,
-
-    -- | These are the special fusion cases for combining each loop form perfectly. 
-    fuseAccAccEFL, fuseAccNoAccEFL, fuseNoAccAccEFL, fuseNoAccNoAccEFL,
-    fuseMapAccEFL, fuseAccMapEFL, fuseMapNoAccEFL, fuseNoAccMapEFL,
-    fuseMapMapEFL, fuseAccFilterEFL, fuseFilterAccEFL, fuseNoAccFilterEFL,
-    fuseFilterNoAccEFL, fuseFilterFilterEFL, fuseMapFilterEFL, fuseFilterMapEFL,
-
-    -- * Strict pairs and sums
-    PairS(..), MaybeS(..)
+    -- A place holder for Stream Fusion
 
   ) where
 
-import Data.ByteString.Internal
-import qualified Data.ByteString.Lazy.Internal as L
-
-import Foreign.ForeignPtr
-import Foreign.Ptr
-import Foreign.Storable         (Storable(..))
-
-import Data.Word                (Word8)
-import System.IO.Unsafe         (unsafePerformIO)
-
--- -----------------------------------------------------------------------------
---
--- Useful macros, until we have bang patterns
---
-
-#define STRICT1(f) f a | a `seq` False = undefined
-#define STRICT2(f) f a b | a `seq` b `seq` False = undefined
-#define STRICT3(f) f a b c | a `seq` b `seq` c `seq` False = undefined
-#define STRICT4(f) f a b c d | a `seq` b `seq` c `seq` d `seq` False = undefined
-#define STRICT5(f) f a b c d e | a `seq` b `seq` c `seq` d `seq` e `seq` False = undefined
-
-infixl 2 :*:
-
--- |Strict pair
-data PairS a b = !a :*: !b deriving (Eq,Ord,Show)
-
--- |Strict Maybe
-data MaybeS a = NothingS | JustS !a deriving (Eq,Ord,Show)
-
--- |Data type for accumulators which can be ignored. The rewrite rules rely on
--- the fact that no bottoms of this type are ever constructed; hence, we can
--- assume @(_ :: NoAcc) `seq` x = x@.
---
-data NoAcc = NoAcc
-
--- |Type of loop functions
-type AccEFL acc = acc -> Word8 -> (PairS acc (MaybeS Word8))
-type NoAccEFL   =        Word8 ->             MaybeS Word8
-type MapEFL     =        Word8 ->                    Word8
-type FilterEFL  =        Word8 ->             Bool
-
-infixr 9 `fuseEFL`
-
--- |Fuse to flat loop functions
-fuseEFL :: AccEFL acc1 -> AccEFL acc2 -> AccEFL (PairS acc1 acc2)
-fuseEFL f g (acc1 :*: acc2) e1 =
-    case f acc1 e1 of
-        acc1' :*: NothingS -> (acc1' :*: acc2) :*: NothingS
-        acc1' :*: JustS e2 ->
-            case g acc2 e2 of
-                acc2' :*: res -> (acc1' :*: acc2') :*: res
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] fuseEFL #-}
-#endif
-
--- | Special forms of loop arguments
---
--- * These are common special cases for the three function arguments of gen
---   and loop; we give them special names to make it easier to trigger RULES
---   applying in the special cases represented by these arguments.  The
---   "INLINE [1]" makes sure that these functions are only inlined in the last
---   two simplifier phases.
---
--- * In the case where the accumulator is not needed, it is better to always
---   explicitly return a value `()', rather than just copy the input to the
---   output, as the former gives GHC better local information.
--- 
-
--- | Element function expressing a mapping only
-#if !defined(LOOPNOACC_FUSION)
-mapEFL :: (Word8 -> Word8) -> AccEFL NoAcc
-mapEFL f = \_ e -> (NoAcc :*: (JustS $ f e))
-#else
-mapEFL :: (Word8 -> Word8) -> NoAccEFL
-mapEFL f = \e -> JustS (f e)
-#endif
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] mapEFL #-}
-#endif
-
--- | Element function implementing a filter function only
-#if !defined(LOOPNOACC_FUSION)
-filterEFL :: (Word8 -> Bool) -> AccEFL NoAcc
-filterEFL p = \_ e -> if p e then (NoAcc :*: JustS e) else (NoAcc :*: NothingS)
-#else
-filterEFL :: (Word8 -> Bool) -> NoAccEFL
-filterEFL p = \e -> if p e then JustS e else NothingS
-#endif
-
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] filterEFL #-}
-#endif
-
--- |Element function expressing a reduction only
-foldEFL :: (acc -> Word8 -> acc) -> AccEFL acc
-foldEFL f = \a e -> (f a e :*: NothingS)
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] foldEFL #-}
-#endif
-
--- | A strict foldEFL.
-foldEFL' :: (acc -> Word8 -> acc) -> AccEFL acc
-foldEFL' f = \a e -> let a' = f a e in a' `seq` (a' :*: NothingS)
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] foldEFL' #-}
-#endif
-
--- | Element function expressing a prefix reduction only
---
-scanEFL :: (Word8 -> Word8 -> Word8) -> AccEFL Word8
-scanEFL f = \a e -> (f a e :*: JustS a)
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] scanEFL #-}
-#endif
-
--- | Element function implementing a map and fold
---
-mapAccumEFL :: (acc -> Word8 -> (acc, Word8)) -> AccEFL acc
-mapAccumEFL f = \a e -> case f a e of (a', e') -> (a' :*: JustS e')
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] mapAccumEFL #-}
-#endif
-
--- | Element function implementing a map with index
---
-mapIndexEFL :: (Int -> Word8 -> Word8) -> AccEFL Int
-mapIndexEFL f = \i e -> let i' = i+1 in i' `seq` (i' :*: JustS (f i e))
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] mapIndexEFL #-}
-#endif
-
--- | Projection functions that are fusion friendly (as in, we determine when
--- they are inlined)
-loopArr :: (PairS acc arr) -> arr
-loopArr (_ :*: arr) = arr
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] loopArr #-}
-#endif
-
-loopAcc :: (PairS acc arr) -> acc
-loopAcc (acc :*: _) = acc
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] loopAcc #-}
-#endif
-
-loopSndAcc :: (PairS (PairS acc1 acc2) arr) -> (PairS acc2 arr)
-loopSndAcc ((_ :*: acc) :*: arr) = (acc :*: arr)
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] loopSndAcc #-}
-#endif
-
-unSP :: (PairS acc arr) -> (acc, arr)
-unSP (acc :*: arr) = (acc, arr)
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] unSP #-}
-#endif
-
-------------------------------------------------------------------------
---
--- Loop combinator and fusion rules for flat arrays
--- |Iteration over over ByteStrings
-
--- | Iteration over over ByteStrings
-loopU :: AccEFL acc                 -- ^ mapping & folding, once per elem
-      -> acc                        -- ^ initial acc value
-      -> ByteString                 -- ^ input ByteString
-      -> (PairS acc ByteString)
-
-loopU f start (PS z s i) = unsafePerformIO $ withForeignPtr z $ \a -> do
-    (ps, acc) <- createAndTrim' i $ \p -> do
-      (acc' :*: i') <- go (a `plusPtr` s) p start
-      return (0, i', acc')
-    return (acc :*: ps)
-
-  where
-    go p ma = trans 0 0
-        where
-            STRICT3(trans)
-            trans a_off ma_off acc
-                | a_off >= i = return (acc :*: ma_off)
-                | otherwise  = do
-                    x <- peekByteOff p a_off
-                    let (acc' :*: oe) = f acc x
-                    ma_off' <- case oe of
-                        NothingS -> return ma_off
-                        JustS e  -> do pokeByteOff ma ma_off e
-                                       return $ ma_off + 1
-                    trans (a_off+1) ma_off' acc'
-
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] loopU #-}
-#endif
-
-{-# RULES
-
-"FPS loop/loop fusion!" forall em1 em2 start1 start2 arr.
-  loopU em2 start2 (loopArr (loopU em1 start1 arr)) =
-    loopSndAcc (loopU (em1 `fuseEFL` em2) (start1 :*: start2) arr)
-
-  #-}
-
---
--- Functional list/array fusion for lazy ByteStrings.
---
-loopL :: AccEFL acc          -- ^ mapping & folding, once per elem
-      -> acc                 -- ^ initial acc value
-      -> L.ByteString        -- ^ input ByteString
-      -> PairS acc L.ByteString
-loopL f = loop
-  where loop s L.Empty     = (s :*: L.Empty)
-        loop s (L.Chunk x xs)
-          | l == 0    = (s'' :*: ys)
-          | otherwise = (s'' :*: L.Chunk y ys)
-          where (s'  :*: y@(PS _ _ l)) = loopU f s x -- avoid circular dep on S.null
-                (s'' :*: ys)           = loop s' xs
-
-#if defined(__GLASGOW_HASKELL__)
-{-# INLINE [1] loopL #-}
-#endif
-
-{-# RULES
-
-"FPS lazy loop/loop fusion!" forall em1 em2 start1 start2 arr.
-  loopL em2 start2 (loopArr (loopL em1 start1 arr)) =
-    loopSndAcc (loopL (em1 `fuseEFL` em2) (start1 :*: start2) arr)
-
-  #-}
-
-
-{-
-
-Alternate experimental formulation of loopU which partitions it into
-an allocating wrapper and an imperitive array-mutating loop.
-
-The point in doing this split is that we might be able to fuse multiple
-loops into a single wrapper. This would save reallocating another buffer.
-It should also give better cache locality by reusing the buffer.
-
-Note that this stuff needs ghc-6.5 from May 26 or later for the RULES to
-really work reliably.
-
--}
-
-loopUp :: AccEFL acc -> acc -> ByteString -> PairS acc ByteString
-loopUp f a arr = loopWrapper (doUpLoop f a) arr
-{-# INLINE loopUp #-}
-
-loopDown :: AccEFL acc -> acc -> ByteString -> PairS acc ByteString
-loopDown f a arr = loopWrapper (doDownLoop f a) arr
-{-# INLINE loopDown #-}
-
-loopNoAcc :: NoAccEFL -> ByteString -> PairS NoAcc ByteString
-loopNoAcc f arr = loopWrapper (doNoAccLoop f NoAcc) arr
-{-# INLINE loopNoAcc #-}
-
-loopMap :: MapEFL -> ByteString -> PairS NoAcc ByteString
-loopMap f arr = loopWrapper (doMapLoop f NoAcc) arr
-{-# INLINE loopMap #-}
-
-loopFilter :: FilterEFL -> ByteString -> PairS NoAcc ByteString
-loopFilter f arr = loopWrapper (doFilterLoop f NoAcc) arr
-{-# INLINE loopFilter #-}
-
--- The type of imperitive loops that fill in a destination array by
--- reading a source array. They may not fill in the whole of the dest
--- array if the loop is behaving as a filter, this is why we return
--- the length that was filled in. The loop may also accumulate some
--- value as it loops over the source array.
---
-type ImperativeLoop acc =
-    Ptr Word8          -- pointer to the start of the source byte array
- -> Ptr Word8          -- pointer to ther start of the destination byte array
- -> Int                -- length of the source byte array
- -> IO (PairS (PairS acc Int) Int) -- result and offset, length of dest that was filled
-
-loopWrapper :: ImperativeLoop acc -> ByteString -> PairS acc ByteString
-loopWrapper body (PS srcFPtr srcOffset srcLen) = unsafePerformIO $
-    withForeignPtr srcFPtr $ \srcPtr -> do
-    (ps, acc) <- createAndTrim' srcLen $ \destPtr -> do
-        (acc :*: destOffset :*: destLen) <-
-          body (srcPtr `plusPtr` srcOffset) destPtr srcLen
-        return (destOffset, destLen, acc)
-    return (acc :*: ps)
-
-doUpLoop :: AccEFL acc -> acc -> ImperativeLoop acc
-doUpLoop f acc0 src dest len = loop 0 0 acc0
-  where STRICT3(loop)
-        loop src_off dest_off acc
-            | src_off >= len = return (acc :*: 0 :*: dest_off)
-            | otherwise      = do
-                x <- peekByteOff src src_off
-                case f acc x of
-                  (acc' :*: NothingS) -> loop (src_off+1) dest_off acc'
-                  (acc' :*: JustS x') -> pokeByteOff dest dest_off x'
-                                      >> loop (src_off+1) (dest_off+1) acc'
-
-doDownLoop :: AccEFL acc -> acc -> ImperativeLoop acc
-doDownLoop f acc0 src dest len = loop (len-1) (len-1) acc0
-  where STRICT3(loop)
-        loop src_off dest_off acc
-            | src_off < 0 = return (acc :*: dest_off + 1 :*: len - (dest_off + 1))
-            | otherwise   = do
-                x <- peekByteOff src src_off
-                case f acc x of
-                  (acc' :*: NothingS) -> loop (src_off-1) dest_off acc'
-                  (acc' :*: JustS x') -> pokeByteOff dest dest_off x'
-                                      >> loop (src_off-1) (dest_off-1) acc'
-
-doNoAccLoop :: NoAccEFL -> noAcc -> ImperativeLoop noAcc
-doNoAccLoop f noAcc src dest len = loop 0 0
-  where STRICT2(loop)
-        loop src_off dest_off
-            | src_off >= len = return (noAcc :*: 0 :*: dest_off)
-            | otherwise      = do
-                x <- peekByteOff src src_off
-                case f x of
-                  NothingS -> loop (src_off+1) dest_off
-                  JustS x' -> pokeByteOff dest dest_off x'
-                           >> loop (src_off+1) (dest_off+1)
-
-doMapLoop :: MapEFL -> noAcc -> ImperativeLoop noAcc
-doMapLoop f noAcc src dest len = loop 0
-  where STRICT1(loop)
-        loop n
-            | n >= len = return (noAcc :*: 0 :*: len)
-            | otherwise      = do
-                x <- peekByteOff src n
-                pokeByteOff dest n (f x)
-                loop (n+1) -- offset always the same, only pass 1 arg
-
-doFilterLoop :: FilterEFL -> noAcc -> ImperativeLoop noAcc
-doFilterLoop f noAcc src dest len = loop 0 0
-  where STRICT2(loop)
-        loop src_off dest_off
-            | src_off >= len = return (noAcc :*: 0 :*: dest_off)
-            | otherwise      = do
-                x <- peekByteOff src src_off
-                if f x
-                  then pokeByteOff dest dest_off x
-                    >> loop (src_off+1) (dest_off+1)
-                  else loop (src_off+1) dest_off
-
--- run two loops in sequence,
--- think of it as: loop1 >> loop2
-sequenceLoops :: ImperativeLoop acc1
-              -> ImperativeLoop acc2
-              -> ImperativeLoop (PairS acc1 acc2)
-sequenceLoops loop1 loop2 src dest len0 = do
-  (acc1 :*: off1 :*: len1) <- loop1 src dest len0
-  (acc2 :*: off2 :*: len2) <-
-    let src'  = dest `plusPtr` off1
-        dest' = src' -- note that we are using dest == src
-                     -- for the second loop as we are
-                     -- mutating the dest array in-place!
-     in loop2 src' dest' len1
-  return ((acc1  :*: acc2) :*: off1 + off2 :*: len2)
-
-  -- TODO: prove that this is associative! (I think it is)
-  -- since we can't be sure how the RULES will combine loops.
-
-#if defined(__GLASGOW_HASKELL__)
-
-{-# INLINE [1] doUpLoop             #-}
-{-# INLINE [1] doDownLoop           #-}
-{-# INLINE [1] doNoAccLoop          #-}
-{-# INLINE [1] doMapLoop            #-}
-{-# INLINE [1] doFilterLoop         #-}
-
-{-# INLINE [1] loopWrapper          #-}
-{-# INLINE [1] sequenceLoops        #-}
-
-{-# INLINE [1] fuseAccAccEFL        #-}
-{-# INLINE [1] fuseAccNoAccEFL      #-}
-{-# INLINE [1] fuseNoAccAccEFL      #-}
-{-# INLINE [1] fuseNoAccNoAccEFL    #-}
-{-# INLINE [1] fuseMapAccEFL        #-}
-{-# INLINE [1] fuseAccMapEFL        #-}
-{-# INLINE [1] fuseMapNoAccEFL      #-}
-{-# INLINE [1] fuseNoAccMapEFL      #-}
-{-# INLINE [1] fuseMapMapEFL        #-}
-{-# INLINE [1] fuseAccFilterEFL     #-}
-{-# INLINE [1] fuseFilterAccEFL     #-}
-{-# INLINE [1] fuseNoAccFilterEFL   #-}
-{-# INLINE [1] fuseFilterNoAccEFL   #-}
-{-# INLINE [1] fuseFilterFilterEFL  #-}
-{-# INLINE [1] fuseMapFilterEFL     #-}
-{-# INLINE [1] fuseFilterMapEFL     #-}
-
-#endif
-
-{-# RULES
-
-"FPS loopArr/loopSndAcc" forall x.
-  loopArr (loopSndAcc x) = loopArr x
-
-"FPS seq/NoAcc" forall (u::NoAcc) e.
-  u `seq` e = e
-
-"FPS loop/loop wrapper elimination" forall loop1 loop2 arr.
-  loopWrapper loop2 (loopArr (loopWrapper loop1 arr)) =
-    loopSndAcc (loopWrapper (sequenceLoops loop1 loop2) arr)
-
---
--- n.b in the following, when reading n/m fusion, recall sequenceLoops
--- is monadic, so its really n >> m fusion (i.e. m.n), not n . m fusion.
---
-
-"FPS up/up loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doUpLoop f1 acc1) (doUpLoop f2 acc2) =
-    doUpLoop (f1 `fuseAccAccEFL` f2) (acc1 :*: acc2)
-
-"FPS map/map loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doMapLoop f1 acc1) (doMapLoop f2 acc2) =
-    doMapLoop (f1 `fuseMapMapEFL` f2) (acc1 :*: acc2)
-
-"FPS filter/filter loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doFilterLoop f1 acc1) (doFilterLoop f2 acc2) =
-    doFilterLoop (f1 `fuseFilterFilterEFL` f2) (acc1 :*: acc2)
-
-"FPS map/filter loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doMapLoop f1 acc1) (doFilterLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseMapFilterEFL` f2) (acc1 :*: acc2)
-
-"FPS filter/map loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doFilterLoop f1 acc1) (doMapLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseFilterMapEFL` f2) (acc1 :*: acc2)
-
-"FPS map/up loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doMapLoop f1 acc1) (doUpLoop f2 acc2) =
-    doUpLoop (f1 `fuseMapAccEFL` f2) (acc1 :*: acc2)
-
-"FPS up/map loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doUpLoop f1 acc1) (doMapLoop f2 acc2) =
-    doUpLoop (f1 `fuseAccMapEFL` f2) (acc1 :*: acc2)
-
-"FPS filter/up loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doFilterLoop f1 acc1) (doUpLoop f2 acc2) =
-    doUpLoop (f1 `fuseFilterAccEFL` f2) (acc1 :*: acc2)
-
-"FPS up/filter loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doUpLoop f1 acc1) (doFilterLoop f2 acc2) =
-    doUpLoop (f1 `fuseAccFilterEFL` f2) (acc1 :*: acc2)
-
-"FPS down/down loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doDownLoop f1 acc1) (doDownLoop f2 acc2) =
-    doDownLoop (f1 `fuseAccAccEFL` f2) (acc1 :*: acc2)
-
-"FPS map/down fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doMapLoop f1 acc1) (doDownLoop f2 acc2) =
-    doDownLoop (f1 `fuseMapAccEFL` f2) (acc1 :*: acc2)
-
-"FPS down/map loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doDownLoop f1 acc1) (doMapLoop f2 acc2) =
-    doDownLoop (f1 `fuseAccMapEFL` f2) (acc1 :*: acc2)
-
-"FPS filter/down fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doFilterLoop f1 acc1) (doDownLoop f2 acc2) =
-    doDownLoop (f1 `fuseFilterAccEFL` f2) (acc1 :*: acc2)
-
-"FPS down/filter loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doDownLoop f1 acc1) (doFilterLoop f2 acc2) =
-    doDownLoop (f1 `fuseAccFilterEFL` f2) (acc1 :*: acc2)
-
-"FPS noAcc/noAcc loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doNoAccLoop f1 acc1) (doNoAccLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseNoAccNoAccEFL` f2) (acc1 :*: acc2)
-
-"FPS noAcc/up loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doNoAccLoop f1 acc1) (doUpLoop f2 acc2) =
-    doUpLoop (f1 `fuseNoAccAccEFL` f2) (acc1 :*: acc2)
-
-"FPS up/noAcc loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doUpLoop f1 acc1) (doNoAccLoop f2 acc2) =
-    doUpLoop (f1 `fuseAccNoAccEFL` f2) (acc1 :*: acc2)
-
-"FPS map/noAcc loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doMapLoop f1 acc1) (doNoAccLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseMapNoAccEFL` f2) (acc1 :*: acc2)
-
-"FPS noAcc/map loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doNoAccLoop f1 acc1) (doMapLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseNoAccMapEFL` f2) (acc1 :*: acc2)
-
-"FPS filter/noAcc loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doFilterLoop f1 acc1) (doNoAccLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseFilterNoAccEFL` f2) (acc1 :*: acc2)
-
-"FPS noAcc/filter loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doNoAccLoop f1 acc1) (doFilterLoop f2 acc2) =
-    doNoAccLoop (f1 `fuseNoAccFilterEFL` f2) (acc1 :*: acc2)
-
-"FPS noAcc/down loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doNoAccLoop f1 acc1) (doDownLoop f2 acc2) =
-    doDownLoop (f1 `fuseNoAccAccEFL` f2) (acc1 :*: acc2)
-
-"FPS down/noAcc loop fusion" forall f1 f2 acc1 acc2.
-  sequenceLoops (doDownLoop f1 acc1) (doNoAccLoop f2 acc2) =
-    doDownLoop (f1 `fuseAccNoAccEFL` f2) (acc1 :*: acc2)
-
-  #-}
-
-{-
-
-up      = up loop
-down    = down loop
-map     = map special case
-filter  = filter special case
-noAcc   = noAcc undirectional loop (unused)
-
-heirarchy:
-  up     down
-   ^     ^
-    \   /
-    noAcc
-     ^ ^
-    /   \
- map     filter
-
-each is a special case of the things above
-
-so we get rules that combine things on the same level
-and rules that combine things on different levels
-to get something on the higher level
-
-so all the cases:
-up/up         --> up     fuseAccAccEFL
-down/down     --> down   fuseAccAccEFL
-noAcc/noAcc   --> noAcc  fuseNoAccNoAccEFL
-
-noAcc/up      --> up     fuseNoAccAccEFL
-up/noAcc      --> up     fuseAccNoAccEFL
-noAcc/down    --> down   fuseNoAccAccEFL
-down/noAcc    --> down   fuseAccNoAccEFL
-
-and if we do the map, filter special cases then it adds a load more:
-
-map/map       --> map    fuseMapMapEFL
-filter/filter --> filter fuseFilterFilterEFL
-
-map/filter    --> noAcc  fuseMapFilterEFL
-filter/map    --> noAcc  fuseFilterMapEFL
-
-map/noAcc     --> noAcc  fuseMapNoAccEFL
-noAcc/map     --> noAcc  fuseNoAccMapEFL
-
-map/up        --> up     fuseMapAccEFL
-up/map        --> up     fuseAccMapEFL
-
-map/down      --> down   fuseMapAccEFL
-down/map      --> down   fuseAccMapEFL
-
-filter/noAcc  --> noAcc  fuseNoAccFilterEFL
-noAcc/filter  --> noAcc  fuseFilterNoAccEFL
-
-filter/up     --> up     fuseFilterAccEFL
-up/filter     --> up     fuseAccFilterEFL
-
-filter/down   --> down   fuseFilterAccEFL
-down/filter   --> down   fuseAccFilterEFL
--}
-
-fuseAccAccEFL :: AccEFL acc1 -> AccEFL acc2 -> AccEFL (PairS acc1 acc2)
-fuseAccAccEFL f g (acc1 :*: acc2) e1 =
-    case f acc1 e1 of
-        acc1' :*: NothingS -> (acc1' :*: acc2) :*: NothingS
-        acc1' :*: JustS e2 ->
-            case g acc2 e2 of
-                acc2' :*: res -> (acc1' :*: acc2') :*: res
-
-fuseAccNoAccEFL :: AccEFL acc -> NoAccEFL -> AccEFL (PairS acc noAcc)
-fuseAccNoAccEFL f g (acc :*: noAcc) e1 =
-    case f acc e1 of
-        acc' :*: NothingS -> (acc' :*: noAcc) :*: NothingS
-        acc' :*: JustS e2 -> (acc' :*: noAcc) :*: g e2
-
-fuseNoAccAccEFL :: NoAccEFL -> AccEFL acc -> AccEFL (PairS noAcc acc)
-fuseNoAccAccEFL f g (noAcc :*: acc) e1 =
-    case f e1 of
-        NothingS -> (noAcc :*: acc) :*: NothingS
-        JustS e2 ->
-            case g acc e2 of
-                acc' :*: res -> (noAcc :*: acc') :*: res
-
-fuseNoAccNoAccEFL :: NoAccEFL -> NoAccEFL -> NoAccEFL
-fuseNoAccNoAccEFL f g e1 =
-    case f e1 of
-        NothingS -> NothingS
-        JustS e2 -> g e2
-
-fuseMapAccEFL :: MapEFL -> AccEFL acc -> AccEFL (PairS noAcc acc)
-fuseMapAccEFL f g (noAcc :*: acc) e1 =
-    case g acc (f e1) of
-        (acc' :*: res) -> (noAcc :*: acc') :*: res
-
-fuseAccMapEFL :: AccEFL acc -> MapEFL -> AccEFL (PairS acc noAcc)
-fuseAccMapEFL f g (acc :*: noAcc) e1 =
-    case f acc e1 of
-        (acc' :*: NothingS) -> (acc' :*: noAcc) :*: NothingS
-        (acc' :*: JustS e2) -> (acc' :*: noAcc) :*: JustS (g e2)
-
-fuseMapMapEFL :: MapEFL -> MapEFL -> MapEFL
-fuseMapMapEFL   f g e1 = g (f e1)     -- n.b. perfect fusion
-
-fuseMapNoAccEFL :: MapEFL -> NoAccEFL -> NoAccEFL
-fuseMapNoAccEFL f g e1 = g (f e1)
-
-fuseNoAccMapEFL :: NoAccEFL -> MapEFL -> NoAccEFL
-fuseNoAccMapEFL f g e1 =
-    case f e1 of
-        NothingS -> NothingS
-        JustS e2 -> JustS (g e2)
-
-fuseAccFilterEFL :: AccEFL acc -> FilterEFL -> AccEFL (PairS acc noAcc)
-fuseAccFilterEFL f g (acc :*: noAcc) e1 =
-    case f acc e1 of
-        acc' :*: NothingS -> (acc' :*: noAcc) :*: NothingS
-        acc' :*: JustS e2 ->
-            case g e2 of
-                False -> (acc' :*: noAcc) :*: NothingS
-                True  -> (acc' :*: noAcc) :*: JustS e2
-
-fuseFilterAccEFL :: FilterEFL -> AccEFL acc -> AccEFL (PairS noAcc acc)
-fuseFilterAccEFL f g (noAcc :*: acc) e1 =
-    case f e1 of
-        False -> (noAcc :*: acc) :*: NothingS
-        True  ->
-            case g acc e1 of
-                acc' :*: res -> (noAcc :*: acc') :*: res
-
-fuseNoAccFilterEFL :: NoAccEFL -> FilterEFL -> NoAccEFL
-fuseNoAccFilterEFL f g e1 =
-    case f e1 of
-        NothingS -> NothingS
-        JustS e2 ->
-            case g e2 of
-                False -> NothingS
-                True  -> JustS e2
-
-fuseFilterNoAccEFL :: FilterEFL -> NoAccEFL -> NoAccEFL
-fuseFilterNoAccEFL f g e1 =
-    case f e1 of
-        False -> NothingS
-        True  -> g e1
-
-fuseFilterFilterEFL :: FilterEFL -> FilterEFL -> FilterEFL
-fuseFilterFilterEFL f g e1 = f e1 && g e1
-
-fuseMapFilterEFL :: MapEFL -> FilterEFL -> NoAccEFL
-fuseMapFilterEFL f g e1 =
-    case f e1 of
-        e2 -> case g e2 of
-            False -> NothingS
-            True  -> JustS e2
-
-fuseFilterMapEFL :: FilterEFL -> MapEFL -> NoAccEFL
-fuseFilterMapEFL f g e1 =
-    case f e1 of
-        False -> NothingS
-        True  -> JustS (g e1)
 
diff --git a/Data/ByteString/Internal.hs b/Data/ByteString/Internal.hs
--- a/Data/ByteString/Internal.hs
+++ b/Data/ByteString/Internal.hs
@@ -1,4 +1,5 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts #-}
+{-# LANGUAGE CPP, ForeignFunctionInterface #-}
+{-# OPTIONS_GHC -XUnliftedFFITypes -XMagicHash -XUnboxedTuples -XDeriveDataTypeable #-}
 -- |
 -- Module      : Data.ByteString.Internal
 -- License     : BSD-style
@@ -39,7 +40,6 @@
         memchr,                 -- :: Ptr Word8 -> Word8 -> CSize -> IO Ptr Word8
         memcmp,                 -- :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
         memcpy,                 -- :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()
-        memmove,                -- :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()
         memset,                 -- :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)
 
         -- * cbits functions
@@ -76,8 +76,13 @@
 import Data.Generics            (Data(..), Typeable(..))
 import GHC.Ptr                  (Ptr(..))
 import GHC.Base                 (realWorld#,unsafeChr)
-import GHC.IOBase               (IO(IO), unsafePerformIO, RawBuffer)
+import GHC.IOBase               (IO(IO), RawBuffer)
+#if __GLASGOW_HASKELL__ >= 608
+import GHC.IOBase               (unsafeDupablePerformIO)
 #else
+import GHC.IOBase               (unsafePerformIO)
+#endif
+#else
 import Data.Char                (chr)
 import System.IO.Unsafe         (unsafePerformIO)
 #endif
@@ -199,9 +204,15 @@
 -- 'createAndTrim' the ByteString is not reallocated if the final size
 -- is less than the estimated size.
 unsafeCreate :: Int -> (Ptr Word8 -> IO ()) -> ByteString
-unsafeCreate l f = unsafePerformIO (create l f)
+unsafeCreate l f = unsafeDupablePerformIO (create l f)
 {-# INLINE unsafeCreate #-}
 
+#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 608
+-- for Hugs   
+unsafeDupablePerformIO :: IO a -> a
+unsafeDupablePerformIO = unsafePerformIO
+#endif
+
 -- | Create ByteString of size @l@ and use action @f@ to fill it's contents.
 create :: Int -> (Ptr Word8 -> IO ()) -> IO ByteString
 create l f = do
@@ -334,12 +345,14 @@
 memcpy :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()
 memcpy p q s = c_memcpy p q s >> return ()
 
+{-
 foreign import ccall unsafe "string.h memmove" c_memmove
     :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
 
 memmove :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()
 memmove p q s = do c_memmove p q s
                    return ()
+-}
 
 foreign import ccall unsafe "string.h memset" c_memset
     :: Ptr Word8 -> CInt -> CSize -> IO (Ptr Word8)
diff --git a/Data/ByteString/Lazy.hs b/Data/ByteString/Lazy.hs
--- a/Data/ByteString/Lazy.hs
+++ b/Data/ByteString/Lazy.hs
@@ -1,4 +1,5 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans -fno-warn-incomplete-patterns #-}
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
 
 -- #prune
 
@@ -101,7 +102,6 @@
         -- ** Accumulating maps
         mapAccumL,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)
         mapAccumR,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)
-        mapIndexed,             -- :: (Int64 -> Word8 -> Word8) -> ByteString -> ByteString
 
         -- ** Infinite ByteStrings
         repeat,                 -- :: Word8 -> ByteString
@@ -193,13 +193,6 @@
         hPut,                   -- :: Handle -> ByteString -> IO ()
         hPutStr,                -- :: Handle -> ByteString -> IO ()
 
---      hGetN,                  -- :: Int -> Handle -> Int -> IO ByteString
---      hGetContentsN,          -- :: Int -> Handle -> IO ByteString
---      hGetNonBlockingN,       -- :: Int -> Handle -> IO ByteString
-
-        -- undocumented deprecated things:
-        join                    -- :: ByteString -> [ByteString] -> ByteString
-
   ) where
 
 import qualified Prelude
@@ -215,7 +208,6 @@
 import qualified Data.ByteString.Internal as S
 import qualified Data.ByteString.Unsafe as S
 import Data.ByteString.Lazy.Internal
-import qualified Data.ByteString.Fusion as F
 
 import Data.Monoid              (Monoid(..))
 
@@ -593,10 +585,6 @@
         where (s'', c') = S.mapAccumR f s' c
               (s', cs') = go s cs
 
--- | /O(n)/ map Word8 functions, provided with the index at each position
-mapIndexed :: (Int -> Word8 -> Word8) -> ByteString -> ByteString
-mapIndexed f = F.loopArr . F.loopL (F.mapIndexEFL f) 0
-
 -- ---------------------------------------------------------------------
 -- Building ByteStrings
 
@@ -609,7 +597,9 @@
 --
 -- > last (scanl f z xs) == foldl f z xs.
 scanl :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString
-scanl f z ps = F.loopArr . F.loopL (F.scanEFL f) z $ (ps `snoc` 0)
+scanl f z = snd . foldl k (z,singleton z)
+ where
+    k (c,acc) a = let n = f c a in (n, acc `snoc` n)
 {-# INLINE scanl #-}
 
 -- ---------------------------------------------------------------------
@@ -905,10 +895,6 @@
 intercalate :: ByteString -> [ByteString] -> ByteString
 intercalate s = concat . (L.intersperse s)
 
-join :: ByteString -> [ByteString] -> ByteString
-join = intercalate
-{-# DEPRECATED join "use intercalate" #-}
-
 -- ---------------------------------------------------------------------
 -- Indexing ByteStrings
 
@@ -1024,10 +1010,9 @@
     where
         go Empty        = Empty
         go (Chunk x xs) = chunk (S.filter p x) (go xs)
-#if __GLASGOW_HASKELL__
-{-# INLINE [1] filter #-}
-#endif
+{-# INLINE filter #-}
 
+{-
 -- | /O(n)/ and /O(n\/c) space/ A first order equivalent of /filter .
 -- (==)/, for the common case of filtering a single byte. It is more
 -- efficient to use /filterByte/ in this case.
@@ -1041,14 +1026,13 @@
 {-# INLINE filterByte #-}
 
 {-# RULES
-  "FPS specialise filter (== x)" forall x.
-      filter ((==) x) = filterByte x
-  #-}
+"ByteString specialise filter (== x)" forall x.
+  filter ((==) x) = filterByte x
 
-{-# RULES
-  "FPS specialise filter (== x)" forall x.
-     filter (== x) = filterByte x
+"ByteString specialise filter (== x)" forall x.
+ filter (== x) = filterByte x
   #-}
+-}
 
 {-
 -- | /O(n)/ A first order equivalent of /filter . (\/=)/, for the common
diff --git a/Data/ByteString/Lazy/Char8.hs b/Data/ByteString/Lazy/Char8.hs
--- a/Data/ByteString/Lazy/Char8.hs
+++ b/Data/ByteString/Lazy/Char8.hs
@@ -1,4 +1,5 @@
-{-# OPTIONS_GHC -cpp -fno-warn-orphans #-}
+{-# LANGUAGE CPP #-}
+{-# GHC_OPTIONS -fno-warn-orphans #-}
 
 -- #prune
 
@@ -80,7 +81,7 @@
 
         -- ** Accumulating maps
         mapAccumL,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)
-        mapIndexed,             -- :: (Int64 -> Char -> Char) -> ByteString -> ByteString
+        mapAccumR,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)
 
         -- ** Infinite ByteStrings
         repeat,                 -- :: Char -> ByteString
@@ -174,13 +175,6 @@
         hGetNonBlocking,        -- :: Handle -> Int64 -> IO ByteString
         hPut,                   -- :: Handle -> ByteString -> IO ()
 
---      hGetN,                  -- :: Int -> Handle -> Int64 -> IO ByteString
---      hGetContentsN,          -- :: Int -> Handle -> IO ByteString
---      hGetNonBlockingN,       -- :: Int -> Handle -> IO ByteString
-
-        -- undocumented deprecated things:
-        join                    -- :: ByteString -> [ByteString] -> ByteString
-
   ) where
 
 -- Functions transparently exported
@@ -308,10 +302,6 @@
 intersperse = L.intersperse . c2w
 {-# INLINE intersperse #-}
 
-join :: ByteString -> [ByteString] -> ByteString
-join = intercalate
-{-# DEPRECATED join "use intercalate" #-}
-
 -- | 'foldl', applied to a binary operator, a starting value (typically
 -- the left-identity of the operator), and a ByteString, reduces the
 -- ByteString using the binary operator, from left to right.
@@ -395,9 +385,12 @@
 mapAccumL :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)
 mapAccumL f = L.mapAccumL (\a w -> case f a (w2c w) of (a',c) -> (a', c2w c))
 
--- | /O(n)/ map Char functions, provided with the index at each position
-mapIndexed :: (Int -> Char -> Char) -> ByteString -> ByteString
-mapIndexed f = L.mapIndexed (\i w -> c2w (f i (w2c w)))
+-- | The 'mapAccumR' function behaves like a combination of 'map' and
+-- 'foldr'; it applies a function to each element of a ByteString,
+-- passing an accumulating parameter from right to left, and returning a
+-- final value of this accumulator together with the new ByteString.
+mapAccumR :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)
+mapAccumR f = L.mapAccumR (\acc w -> case f acc (w2c w) of (acc', c) -> (acc', c2w c))
 
 ------------------------------------------------------------------------
 -- Generating and unfolding ByteStrings
@@ -573,13 +566,14 @@
 -- predicate.
 filter :: (Char -> Bool) -> ByteString -> ByteString
 filter f = L.filter (f . w2c)
-{-# INLINE [1] filter #-}
+{-# INLINE filter #-}
 
+{-
 -- | /O(n)/ and /O(n\/c) space/ A first order equivalent of /filter .
 -- (==)/, for the common case of filtering a single Char. It is more
 -- efficient to use /filterChar/ in this case.
 --
--- > filterByte == filter . (==)
+-- > filterChar == filter . (==)
 --
 -- filterChar is around 10x faster, and uses much less space, than its
 -- filter equivalent
@@ -589,14 +583,15 @@
 {-# INLINE filterChar #-}
 
 {-# RULES
-  "FPS specialise filter (== x)" forall x.
+  "ByteString specialise filter (== x)" forall x.
       filter ((==) x) = filterChar x
   #-}
 
 {-# RULES
-  "FPS specialise filter (== x)" forall x.
+  "ByteString specialise filter (== x)" forall x.
      filter (== x) = filterChar x
   #-}
+-}
 
 -- | /O(n)/ The 'find' function takes a predicate and a ByteString,
 -- and returns the first element in matching the predicate, or 'Nothing'
diff --git a/Data/ByteString/Lazy/Internal.hs b/Data/ByteString/Lazy/Internal.hs
--- a/Data/ByteString/Lazy/Internal.hs
+++ b/Data/ByteString/Lazy/Internal.hs
@@ -1,4 +1,5 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts #-}
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -XDeriveDataTypeable #-}
 -- |
 -- Module      : Data.ByteString.Lazy.Internal
 -- License     : BSD-style
diff --git a/Data/ByteString/Unsafe.hs b/Data/ByteString/Unsafe.hs
--- a/Data/ByteString/Unsafe.hs
+++ b/Data/ByteString/Unsafe.hs
@@ -1,4 +1,5 @@
-{-# OPTIONS_GHC -cpp -fglasgow-exts #-}
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -XMagicHash #-}
 -- |
 -- Module      : Data.ByteString.Unsafe
 -- License     : BSD-style
@@ -133,7 +134,7 @@
 -- boxed string. A unboxed string literal is compiled to a static @char
 -- []@ by GHC. Establishing the length of the string requires a call to
 -- @strlen(3)@, so the Addr# must point to a null-terminated buffer (as
--- is the case with "string"# literals in GHC). Use 'unsafePackAddress'
+-- is the case with "string"# literals in GHC). Use 'unsafePackAddressLen'
 -- if you know the length of the string statically.
 --
 -- An example:
@@ -144,6 +145,9 @@
 -- original Addr# this modification will be reflected in the resulting
 -- @ByteString@, breaking referential transparency.
 --
+-- Note this also won't work if you Add# has embedded '\0' characters in
+-- the string (strlen will fail).
+--
 unsafePackAddress :: Addr# -> IO ByteString
 unsafePackAddress addr# = do
     p <- newForeignPtr_ cstr
@@ -239,12 +243,13 @@
 -- | /O(n)/ Build a @ByteString@ from a malloced @CString@. This value will
 -- have a @free(3)@ finalizer associated to it.
 --
--- This funtion is /unsafe/. If the original @CStringLen@ is later
+-- This funtion is /unsafe/. If the original @CString@ is later
 -- modified, this change will be reflected in the resulting @ByteString@,
 -- breaking referential transparency.
 --
 -- This function is also unsafe if you call its finalizer twice,
--- which will result in a /double free/ error.
+-- which will result in a /double free/ error, or if you pass it
+-- a CString not allocated with 'malloc'.
 --
 unsafePackMallocCString :: CString -> IO ByteString
 unsafePackMallocCString cstr = do
diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -1,10 +1,8 @@
 TODO:
 
     * back port streams fusion code.
-    * check Lazy.groupBy
     * close bug in Lazy.lines
     * show instance for LPS
-    * export chunk sizes
     * ensure memchr / (== c) rules either always work, or we can back door them
     * stress testing
     * strictness testing
diff --git a/bytestring.cabal b/bytestring.cabal
--- a/bytestring.cabal
+++ b/bytestring.cabal
@@ -1,35 +1,35 @@
 Name:                bytestring
-Version:             0.9.0.4
+Version:             0.9.1.0
 Synopsis:            Fast, packed, strict and lazy byte arrays with a list interface
 Description:
     .
     A time and space-efficient implementation of byte vectors using
     packed Word8 arrays, suitable for high performance use, both in terms
     of large data quantities, or high speed requirements. Byte vectors
-    are encoded as strict 'Word8' arrays of bytes, held in a 'ForeignPtr',
-    and can be passed between C and Haskell with little effort.
+    are encoded as strict 'Word8' arrays of bytes, and lazy lists of
+    strict chunks, held in a 'ForeignPtr', and can be passed between C
+    and Haskell with little effort.
     .
+    Test coverage data for this library is available at:
+        <http://code.haskell.org/~dons/tests/bytestring/hpc_index.html>
+    .
 License:             BSD3
 License-file:        LICENSE
 Category:            Data
-Copyright:           Copyright (c) Don Stewart   2005-2007,
+Copyright:           Copyright (c) Don Stewart   2005-2008,
                                (c) Duncan Coutts 2006-2007,
                                (c) David Roundy  2003-2005.
 Author:              Don Stewart, Duncan Coutts
 Maintainer:          dons@galois.com, duncan@haskell.org
 Stability:           provisional
 Homepage:            http://www.cse.unsw.edu.au/~dons/fps.html
-Tested-With:         GHC ==6.8.2, GHC ==6.6.1, GHC ==6.4.2
+Tested-With:         GHC ==6.8.2
 Build-Type:          Simple
 Cabal-Version:       >= 1.2
-
-flag split-base
+extra-source-files:  README TODO
 
 library
-  if flag(split-base)
-    build-depends:   base >= 3, array
-  else
-    build-depends:   base < 3
+  build-depends:     base
   exposed-modules:   Data.ByteString
                      Data.ByteString.Char8
                      Data.ByteString.Unsafe
@@ -38,18 +38,26 @@
                      Data.ByteString.Lazy.Char8
                      Data.ByteString.Lazy.Internal
                      Data.ByteString.Fusion
+
   extensions:        CPP, ForeignFunctionInterface
 
+  if impl(ghc)
+      extensions:  UnliftedFFITypes, MagicHash, UnboxedTuples, DeriveDataTypeable
+
+  ghc-options: -fglasgow-exts
+               -Wall -fno-warn-orphans
+               -O2 -funbox-strict-fields 
+               -fdicts-cheap -fno-method-sharing
+               -fmax-simplifier-iterations10 -fcpr-off
+  --
+  -- -fglasgow-exts needed for local rewrite rules:
+  --
+
   c-sources:         cbits/fpstring.c
   include-dirs:      include
   includes:          fpstring.h
   install-includes:  fpstring.h
 
-  ghc-options: -Wall
-               -fglasgow-exts -O2 -funbox-strict-fields 
-               -fdicts-cheap -fno-method-sharing
-               -fmax-simplifier-iterations10 -fcpr-off
-
   nhc98-options:     -K4M -K3M
   if impl(ghc <= 6.4.2)
-    ghc-options:     -DSLOW_FOREIGN_PTR
+    cc-options:     -DSLOW_FOREIGN_PTR
diff --git a/tests/Bench.hs b/tests/Bench.hs
--- a/tests/Bench.hs
+++ b/tests/Bench.hs
@@ -184,8 +184,8 @@
                            ,101,114,103,32,101,66,111,111,107]))
     ])
     , ("join",
-        [F ({-# SCC "join"          #-}     app $ B.join (B.pack [1,2,3]))
-        ,F ({-# SCC "lazy join"     #-}     app $ L.join (L.pack [1,2,3]))
+        [F ({-# SCC "join"          #-}     app $ B.intercalate (B.pack [1,2,3]))
+        ,F ({-# SCC "lazy join"     #-}     app $ L.intercalate (L.pack [1,2,3]))
     ])
 --  , ("joinWithByte",
 --      [F ({-# SCC "joinWithByte"  #-}     app $ uncurry (B.joinWithByte 32))
@@ -286,8 +286,8 @@
     , ("zipWith'",
         [F ({-# SCC "zipWith'"      #-}     app (uncurry (B.zipWith (+))))
     ])
-    , ("isSubstringOf",
-        [F ({-# SCC "isSubstringOf" #-}     app $ B.isSubstringOf (C.pack "email news"))
+    , ("isInfixOf",
+        [F ({-# SCC "isSubstringOf" #-}     app $ B.isInfixOf     (C.pack "email news"))
     ])
     , ("isSuffixOf",
         [F ({-# SCC "isSuffixOf"    #-}     app $ B.isSuffixOf (C.pack "new eBooks"))
diff --git a/tests/Hash.hs b/tests/Hash.hs
new file mode 100644
--- /dev/null
+++ b/tests/Hash.hs
@@ -0,0 +1,88 @@
+{-# LANGUAGE BangPatterns #-}
+
+import qualified Data.HashTable as T
+import System.Environment
+import Control.Applicative
+import Data.List
+import Data.Ord
+import qualified Data.Map as M
+import qualified Data.ByteString.Char8 as S
+
+import qualified Data.ByteString.Internal as S
+import qualified Data.ByteString.Unsafe   as S
+import Foreign
+
+
+type Table = T.HashTable S.ByteString Int
+
+newTable :: IO Table
+newTable = T.new (==) hash
+
+update :: Table -> S.ByteString -> IO ()
+update t w = do
+    old <- T.lookup t w
+    case old of
+        Just c -> do T.update t w $! c + 1; return ()
+        _      -> T.insert t w 1
+
+main = do
+    [name] <- getArgs
+    t <- newTable
+    S.words <$> S.readFile name >>= mapM_ (update t)
+    xs <- sortBy (flip (comparing snd)) <$> T.toList t
+    print (take 20 xs)
+
+------------------------------------------------------------------------
+-- a different Ord
+
+hash :: S.ByteString -> Int32
+hash ps = go 0 golden
+  where
+    len = S.length ps
+
+    go :: Int -> Int32 -> Int32
+    go !n !acc
+             | n == len  = fromIntegral acc
+             | otherwise = go (n+1)
+                              ((fromIntegral (ps `S.unsafeIndex` n))
+                                   * 0xdeadbeef + hashInt32 acc)
+
+golden :: Int32
+golden = 1013904242 -- = round ((sqrt 5 - 1) * 2^32) :: Int32
+
+hashInt32 :: Int32 -> Int32
+hashInt32 x = mulHi x golden + x
+
+-- hi 32 bits of a x-bit * 32 bit -> 64-bit multiply
+mulHi :: Int32 -> Int32 -> Int32
+mulHi a b = fromIntegral (r `shiftR` 32)
+   where r :: Int64
+         r = fromIntegral a * fromIntegral b
+
+------------------------------------------------------------------------
+
+newtype OrdString = OrdString S.ByteString
+     deriving Show
+
+eq a@(S.PS p s l) b@(S.PS p' s' l')
+         | l /= l'            = False    -- short cut on length
+         | p == p' && s == s' = True     -- short cut for the same string
+         | otherwise          = compare a b == EQ
+  where
+    compare (S.PS fp1 off1 len1) (S.PS fp2 off2 len2) = S.inlinePerformIO $
+        withForeignPtr fp1 $ \p1 ->
+            withForeignPtr fp2 $ \p2 ->
+                cmp (p1 `plusPtr` off1)
+                    (p2 `plusPtr` off2) 0 len1 len2
+
+cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering
+cmp !p1 !p2 !n len1 len2
+      | n == len1 = if n == len2 then return EQ else return LT
+      | n == len2 = return GT
+      | otherwise = do
+          a <- peekByteOff p1 n :: IO Word8
+          b <- peekByteOff p2 n
+          case a `compare` b of
+                EQ -> cmp p1 p2 (n+1) len1 len2
+                LT -> return LT
+                GT -> return GT
diff --git a/tests/Makefile b/tests/Makefile
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,5 +1,6 @@
 GHC=            ghc
-GHCFLAGS=       -cpp -O2 -funbox-strict-fields -no-recomp -v0
+GHCFLAGS=       -cpp -O2 -funbox-strict-fields -v0 -fglasgow-exts -O2 -funbox-strict-fields -fdicts-cheap -fno-method-sharing -fmax-simplifier-iterations10 -fcpr-off
+
 #PKG=            -package fps
 
 #GHC=            /usr/obj/build/compiler/stage2/ghc-inplace
@@ -45,7 +46,7 @@
 # interpreted fast. Just a quick check.
 .PHONY: prop-fast
 prop-fast::
-	runhaskell -i../cbits/fpstring.o Properties.hs 10 
+	runhaskell -i../cbits/fpstring.o Properties.hs 30 
 
 # compiled
 .PHONY: prop-compiled
@@ -61,6 +62,18 @@
 	${GHC} ${PKG} ${GHCFLAGS} --make Properties.hs -o p -package QuickCheck
 	time ./p
 
+# rules-on
+.PHONY: hpc-lite
+hpc-lite: 
+	@echo "Compiled, rules on, with hpc"	
+	rm -f p.tix
+	${GHC} ${GHCFLAGS} ../dist/build/cbits/fpstring.o -ddump-simpl-stats -fhpc --make -i.. Properties.hs -o p -O -fno-ignore-asserts -fasm -frewrite-rules
+	rm Rules.o Rules.hi
+	${GHC} ${GHCFLAGS} -hide-package bytestring ../dist/build/cbits/fpstring.o -ddump-simpl-stats -i.. Rules.hs -O -fno-ignore-asserts -fasm -frewrite-rules ../Data/ByteString/*.o ../Data/ByteString/*/*.o ../Data/ByteString.o -package QuickCheck QuickCheckUtils.o -c -no-recomp
+	${GHC} ${GHCFLAGS} -package QuickCheck ../dist/build/cbits/fpstring.o Properties.o Rules.o QuickCheckUtils.o ../Data/ByteString/*.o ../Data/ByteString/*/*.o ../Data/ByteString.o -o p
+	time ./p 40
+	hpc markup p --exclude=Main --exclude=QuickCheckUtils --exclude=Data.ByteString.Fusion
+
 #
 # test rewriting is correct and working.
 #
@@ -191,3 +204,4 @@
 	rm -f *~ *.o *.hi $(BIN) bench */*.o */*.hi */*~ 
 	rm -f wc letter_frequency spellcheck linesort fuse inline p u fp lazylines lazybuild lazybuildcons
 	rm -f down-fuse zipwith fusionbench unpack groupby
+	rm -rf *.tix *.html .hpc check
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -1,18 +1,33 @@
+{-# LANGUAGE PatternSignatures #-}
 --
 -- Must have rules off, otherwise the fusion rules will replace the rhs
 -- with the lhs, and we only end up testing lhs == lhs
 --
 
+--
+-- -fhpc interferes with rewrite rules firing.
+--
+
+import Foreign
+import Foreign.ForeignPtr
+import Foreign.Marshal.Array
+import GHC.Ptr
 import Test.QuickCheck
+import Control.Monad
+import Control.Concurrent
+import Control.Exception
+import System.Directory
 
 import Data.List
 import Data.Char
 import Data.Word
 import Data.Maybe
 import Data.Int (Int64)
+import Data.Monoid
 
 import Text.Printf
 import Debug.Trace
+import Data.String
 
 import System.Environment
 import System.IO
@@ -25,23 +40,108 @@
 import qualified Data.ByteString.Lazy as L
 import Data.ByteString.Lazy.Internal (ByteString(..))
 
-import qualified Data.ByteString       as P
-import qualified Data.ByteString.Internal as P
-import qualified Data.ByteString.Unsafe as P
-import qualified Data.ByteString.Char8 as C
+import qualified Data.ByteString            as P
+import qualified Data.ByteString.Internal   as P
+import qualified Data.ByteString.Unsafe     as P
+import qualified Data.ByteString.Char8      as C
+
+import qualified Data.ByteString.Lazy.Char8 as LC
 import qualified Data.ByteString.Lazy.Char8 as D
+
+import qualified Data.ByteString.Lazy.Internal as LP
 import Data.ByteString.Fusion
 import Prelude hiding (abs)
 
+import Rules
 import QuickCheckUtils
 
+f = C.dropWhile isSpace
+
 --
+-- ByteString.Lazy.Char8 <=> ByteString.Char8
+--
+
+prop_concatCC       = D.concat      `eq1`  C.concat
+prop_nullCC         = D.null        `eq1`  C.null
+prop_reverseCC      = D.reverse     `eq1`  C.reverse
+prop_transposeCC    = D.transpose   `eq1`  C.transpose
+prop_groupCC        = D.group       `eq1`  C.group
+prop_initsCC        = D.inits       `eq1`  C.inits
+prop_tailsCC        = D.tails       `eq1`  C.tails
+prop_allCC          = D.all         `eq2`  C.all
+prop_anyCC          = D.any         `eq2`  C.any
+prop_appendCC       = D.append      `eq2`  C.append
+prop_breakCC        = D.break       `eq2`  C.break
+prop_concatMapCC    = D.concatMap   `eq2`  C.concatMap
+prop_consCC         = D.cons        `eq2`  C.cons
+prop_unconsCC       = D.uncons      `eq1`  C.uncons
+prop_countCC        = D.count       `eq2`  C.count
+prop_dropCC         = D.drop        `eq2`  C.drop
+prop_dropWhileCC    = D.dropWhile   `eq2`  C.dropWhile
+prop_filterCC       = D.filter      `eq2`  C.filter
+prop_findCC         = D.find        `eq2`  C.find
+prop_findIndexCC    = D.findIndex   `eq2`  C.findIndex
+prop_findIndicesCC  = D.findIndices `eq2`  C.findIndices
+prop_isPrefixOfCC   = D.isPrefixOf  `eq2`  C.isPrefixOf
+prop_mapCC          = D.map         `eq2`  C.map
+prop_replicateCC    = D.replicate   `eq2`  C.replicate
+prop_snocCC         = D.snoc        `eq2`  C.snoc
+prop_spanCC         = D.span        `eq2`  C.span
+prop_splitCC        = D.split       `eq2`  C.split
+prop_splitAtCC      = D.splitAt     `eq2`  C.splitAt
+prop_takeCC         = D.take        `eq2`  C.take
+prop_takeWhileCC    = D.takeWhile   `eq2`  C.takeWhile
+prop_elemCC         = D.elem        `eq2`  C.elem
+prop_notElemCC      = D.notElem     `eq2`  C.notElem
+prop_elemIndexCC    = D.elemIndex   `eq2`  C.elemIndex
+prop_elemIndicesCC  = D.elemIndices `eq2`  C.elemIndices
+prop_lengthCC       = D.length      `eq1`  (fromIntegral . C.length :: C.ByteString -> Int64)
+
+prop_headCC         = D.head        `eqnotnull1` C.head
+prop_initCC         = D.init        `eqnotnull1` C.init
+prop_lastCC         = D.last        `eqnotnull1` C.last
+prop_maximumCC      = D.maximum     `eqnotnull1` C.maximum
+prop_minimumCC      = D.minimum     `eqnotnull1` C.minimum
+prop_tailCC         = D.tail        `eqnotnull1` C.tail
+prop_foldl1CC       = D.foldl1      `eqnotnull2` C.foldl1
+prop_foldl1CC'      = D.foldl1'     `eqnotnull2` C.foldl1'
+prop_foldr1CC       = D.foldr1      `eqnotnull2` C.foldr1
+prop_foldr1CC'      = D.foldr1      `eqnotnull2` C.foldr1'
+prop_scanlCC        = D.scanl       `eqnotnull3` C.scanl
+
+prop_intersperseCC = D.intersperse  `eq2` C.intersperse
+
+prop_foldlCC     = eq3
+    (D.foldl     :: (X -> Char -> X) -> X -> B -> X)
+    (C.foldl     :: (X -> Char -> X) -> X -> P -> X)
+prop_foldlCC'    = eq3
+    (D.foldl'    :: (X -> Char -> X) -> X -> B -> X)
+    (C.foldl'    :: (X -> Char -> X) -> X -> P -> X)
+prop_foldrCC     = eq3
+    (D.foldr     :: (Char -> X -> X) -> X -> B -> X)
+    (C.foldr     :: (Char -> X -> X) -> X -> P -> X)
+prop_foldrCC'    = eq3
+    (D.foldr     :: (Char -> X -> X) -> X -> B -> X)
+    (C.foldr'    :: (Char -> X -> X) -> X -> P -> X)
+prop_mapAccumLCC = eq3
+    (D.mapAccumL :: (X -> Char -> (X,Char)) -> X -> B -> (X, B))
+    (C.mapAccumL :: (X -> Char -> (X,Char)) -> X -> P -> (X, P))
+
+--prop_mapIndexedCC = D.mapIndexed `eq2` C.mapIndexed
+--prop_mapIndexedPL = L.mapIndexed `eq2` P.mapIndexed
+
+--prop_mapAccumL_mapIndexedBP =
+--        P.mapIndexed `eq2`
+--        (\k p -> snd $ P.mapAccumL (\i w -> (i+1, k i w)) (0::Int) p)
+
+--
 -- ByteString.Lazy <=> ByteString
 --
 
 prop_concatBP       = L.concat      `eq1`  P.concat
 prop_nullBP         = L.null        `eq1`  P.null
 prop_reverseBP      = L.reverse     `eq1`  P.reverse
+
 prop_transposeBP    = L.transpose   `eq1`  P.transpose
 prop_groupBP        = L.group       `eq1`  P.group
 prop_initsBP        = L.inits       `eq1`  P.inits
@@ -52,6 +152,9 @@
 prop_breakBP        = L.break       `eq2`  P.break
 prop_concatMapBP    = L.concatMap   `eq2`  P.concatMap
 prop_consBP         = L.cons        `eq2`  P.cons
+prop_consBP'        = L.cons'       `eq2`  P.cons
+prop_consLP'        = LC.cons'      `eq2`  P.cons
+prop_unconsBP       = L.uncons      `eq1`  P.uncons
 prop_countBP        = L.count       `eq2`  P.count
 prop_dropBP         = L.drop        `eq2`  P.drop
 prop_dropWhileBP    = L.dropWhile   `eq2`  P.dropWhile
@@ -72,6 +175,7 @@
 prop_notElemBP      = L.notElem     `eq2`  P.notElem
 prop_elemIndexBP    = L.elemIndex   `eq2`  P.elemIndex
 prop_elemIndicesBP  = L.elemIndices `eq2`  P.elemIndices
+prop_intersperseBP  = L.intersperse  `eq2` P.intersperse
 prop_lengthBP       = L.length      `eq1`  (fromIntegral . P.length :: P.ByteString -> Int64)
 prop_readIntBP      = D.readInt     `eq1`  C.readInt
 prop_linesBP        = D.lines       `eq1`  C.lines
@@ -91,8 +195,10 @@
 prop_foldl1BP       = L.foldl1      `eqnotnull2` P.foldl1
 prop_foldl1BP'      = L.foldl1'     `eqnotnull2` P.foldl1'
 prop_foldr1BP       = L.foldr1      `eqnotnull2` P.foldr1
+prop_foldr1BP'      = L.foldr1      `eqnotnull2` P.foldr1'
 prop_scanlBP        = L.scanl       `eqnotnull3` P.scanl
 
+
 prop_eqBP        = eq2
     ((==) :: B -> B -> Bool)
     ((==) :: P -> P -> Bool)
@@ -108,6 +214,9 @@
 prop_foldrBP     = eq3
     (L.foldr     :: (W -> X -> X) -> X -> B -> X)
     (P.foldr     :: (W -> X -> X) -> X -> P -> X)
+prop_foldrBP'    = eq3
+    (L.foldr     :: (W -> X -> X) -> X -> B -> X)
+    (P.foldr'    :: (W -> X -> X) -> X -> P -> X)
 prop_mapAccumLBP = eq3
     (L.mapAccumL :: (X -> W -> (X,W)) -> X -> B -> (X, B))
     (P.mapAccumL :: (X -> W -> (X,W)) -> X -> P -> (X, P))
@@ -118,6 +227,69 @@
     ((\n f a ->                     fst $
         P.unfoldrN n f a) :: Int -> (X -> Maybe (W,X)) -> X -> P)
 
+prop_unfoldr2BP   = eq2
+    ((\n a -> P.take (n*100) $
+        P.unfoldr    (\x -> if x <= (n*100) then Just (fromIntegral x, x + 1) else Nothing) a)
+                :: Int -> Int -> P)
+    ((\n a ->                     fst $
+        P.unfoldrN (n*100) (\x -> if x <= (n*100) then Just (fromIntegral x, x + 1) else Nothing) a)
+                :: Int -> Int -> P)
+
+prop_unfoldr2CP   = eq2
+    ((\n a -> C.take (n*100) $
+        C.unfoldr    (\x -> if x <= (n*100) then Just (chr (x `mod` 256), x + 1) else Nothing) a)
+                :: Int -> Int -> P)
+    ((\n a ->                     fst $
+        C.unfoldrN (n*100) (\x -> if x <= (n*100) then Just (chr (x `mod` 256), x + 1) else Nothing) a)
+                :: Int -> Int -> P)
+
+
+prop_unfoldrLC   = eq3
+    ((\n f a -> LC.take (fromIntegral n) $
+        LC.unfoldr    f a) :: Int -> (X -> Maybe (Char,X)) -> X -> B)
+    ((\n f a ->                     fst $
+        C.unfoldrN n f a) :: Int -> (X -> Maybe (Char,X)) -> X -> P)
+
+prop_cycleLC  a   = not (LC.null a) ==> eq1
+    ((\n   -> LC.take (fromIntegral n) $
+              LC.cycle a
+     ) :: Int -> B)
+
+    ((\n   -> LC.take (fromIntegral (n::Int)) . LC.concat $
+              unfoldr (\x ->  Just (x,x) ) a
+     ) :: Int -> B)
+
+
+prop_iterateLC   = eq3
+    ((\n f a -> LC.take (fromIntegral n) $
+        LC.iterate  f a) :: Int -> (Char -> Char) -> Char -> B)
+    ((\n f a -> fst $
+        C.unfoldrN n (\a -> Just (f a, f a)) a) :: Int -> (Char -> Char) -> Char -> P)
+
+prop_iterateLC_2   = eq3
+    ((\n f a -> LC.take (fromIntegral n) $
+        LC.iterate  f a) :: Int -> (Char -> Char) -> Char -> B)
+    ((\n f a -> LC.take (fromIntegral n) $
+        LC.unfoldr (\a -> Just (f a, f a)) a) :: Int -> (Char -> Char) -> Char -> B)
+
+prop_iterateL   = eq3
+    ((\n f a -> L.take (fromIntegral n) $
+        L.iterate  f a) :: Int -> (W -> W) -> W -> B)
+    ((\n f a -> fst $
+        P.unfoldrN n (\a -> Just (f a, f a)) a) :: Int -> (W -> W) -> W -> P)
+
+prop_repeatLC   = eq2
+    ((\n a -> LC.take (fromIntegral n) $
+        LC.repeat a) :: Int -> Char -> B)
+    ((\n a -> fst $
+        C.unfoldrN n (\a -> Just (a, a)) a) :: Int -> Char -> P)
+
+prop_repeatL   = eq2
+    ((\n a -> L.take (fromIntegral n) $
+        L.repeat a) :: Int -> W -> B)
+    ((\n a -> fst $
+        P.unfoldrN n (\a -> Just (a, a)) a) :: Int -> W -> P)
+
 --
 -- properties comparing ByteString.Lazy `eq1` List
 --
@@ -184,9 +356,19 @@
 prop_mapAccumLBL  = eq3
     (L.mapAccumL :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
     (  mapAccumL :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
+
 prop_mapAccumRBL  = eq3
     (L.mapAccumR :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
     (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
+
+prop_mapAccumRDL  = eq3
+    (D.mapAccumR :: (X -> Char -> (X,Char)) -> X -> B   -> (X, B))
+    (  mapAccumR :: (X -> Char -> (X,Char)) -> X -> [Char] -> (X, [Char]))
+
+prop_mapAccumRCC  = eq3
+    (C.mapAccumR :: (X -> Char -> (X,Char)) -> X -> P   -> (X, P))
+    (  mapAccumR :: (X -> Char -> (X,Char)) -> X -> [Char] -> (X, [Char]))
+
 prop_unfoldrBL = eq3
     ((\n f a -> L.take (fromIntegral n) $
         L.unfoldr f a) :: Int -> (X -> Maybe (W,X)) -> X -> B)
@@ -214,9 +396,21 @@
 prop_dropPL       = P.drop      `eq2`    (drop      :: Int -> [W] -> [W])
 prop_dropWhilePL  = P.dropWhile `eq2`    (dropWhile :: (W -> Bool) -> [W] -> [W])
 prop_filterPL     = P.filter    `eq2`    (filter    :: (W -> Bool ) -> [W] -> [W])
+prop_filterPL_rule= (\x -> P.filter ((==) x))  `eq2` -- test rules
+                    ((\x -> filter ((==) x)) :: W -> [W] -> [W])
+
+-- under lambda doesn't fire?
+prop_filterLC_rule= (f)  `eq2` -- test rules
+                    ((\x -> filter ((==) x)) :: Char -> [Char] -> [Char])
+    where
+         f x s = LC.filter ((==) x) s
+
+prop_partitionPL  = P.partition `eq2`    (partition :: (W -> Bool ) -> [W] -> ([W],[W]))
+prop_partitionLL  = L.partition `eq2`    (partition :: (W -> Bool ) -> [W] -> ([W],[W]))
 prop_findPL       = P.find      `eq2`    (find      :: (W -> Bool) -> [W] -> Maybe W)
 prop_findIndexPL  = P.findIndex `eq2`    (findIndex :: (W -> Bool) -> [W] -> Maybe Int)
 prop_isPrefixOfPL = P.isPrefixOf`eq2`    (isPrefixOf:: [W] -> [W] -> Bool)
+prop_isInfixOfPL = P.isInfixOf`eq2`       (isInfixOf:: [W] -> [W] -> Bool)
 prop_mapPL        = P.map       `eq2`    (map       :: (W -> W) -> [W] -> [W])
 prop_replicatePL  = P.replicate `eq2`    (replicate :: Int -> W -> [W])
 prop_snocPL       = P.snoc      `eq2`    ((\xs x -> xs ++ [x]) :: [W] -> W -> [W])
@@ -231,7 +425,11 @@
 prop_findIndicesPL= P.findIndices`eq2`   (findIndices:: (W -> Bool) -> [W] -> [Int])
 prop_elemIndicesPL= P.elemIndices`eq2`   (elemIndices:: W -> [W] -> [Int])
 prop_zipPL        = P.zip        `eq2`   (zip :: [W] -> [W] -> [(W,W)])
+prop_zipCL        = C.zip        `eq2`   (zip :: [Char] -> [Char] -> [(Char,Char)])
+prop_zipLL        = L.zip        `eq2`   (zip :: [W] -> [W] -> [(W,W)])
 prop_unzipPL      = P.unzip      `eq1`   (unzip :: [(W,W)] -> ([W],[W]))
+prop_unzipLL      = L.unzip      `eq1`   (unzip :: [(W,W)] -> ([W],[W]))
+prop_unzipCL      = C.unzip      `eq1`   (unzip :: [(Char,Char)] -> ([Char],[Char]))
 
 prop_foldl1PL     = P.foldl1    `eqnotnull2` (foldl1   :: (W -> W -> W) -> [W] -> W)
 prop_foldl1PL'    = P.foldl1'   `eqnotnull2` (foldl1' :: (W -> W -> W) -> [W] -> W)
@@ -247,11 +445,18 @@
 prop_minimumPL    = P.minimum   `eqnotnull1` (minimum   :: [W] -> W)
 prop_tailPL       = P.tail      `eqnotnull1` (tail      :: [W] -> [W])
 
+prop_scanl1CL     = C.scanl1    `eqnotnull2` (scanl1 :: (Char -> Char -> Char) -> [Char] -> [Char])
+prop_scanrCL      = C.scanr     `eqnotnull3` (scanr  :: (Char -> Char -> Char) -> Char -> [Char] -> [Char])
+prop_scanr1CL     = C.scanr1    `eqnotnull2` (scanr1 :: (Char -> Char -> Char) -> [Char] -> [Char])
+
 -- prop_zipWithPL'   = P.zipWith'  `eq3` (zipWith :: (W -> W -> W) -> [W] -> [W] -> [W])
 
 prop_zipWithPL    = (P.zipWith  :: (W -> W -> X) -> P   -> P   -> [X]) `eq3`
                       (zipWith  :: (W -> W -> X) -> [W] -> [W] -> [X])
 
+prop_zipWithPL_rules   = (P.zipWith  :: (W -> W -> W) -> P -> P -> [W]) `eq3`
+                         (zipWith    :: (W -> W -> W) -> [W] -> [W] -> [W])
+
 prop_eqPL      = eq2
     ((==) :: P   -> P   -> Bool)
     ((==) :: [W] -> [W] -> Bool)
@@ -310,6 +515,8 @@
 prop_compare7 x  y  = x  `compare` y  == (L.singleton x `compare` L.singleton y)
 prop_compare8 xs ys = xs `compare` ys == (L.pack xs `compare` L.pack ys)
 
+prop_compare7LL x  y  = x  `compare` y  == (LC.singleton x `compare` LC.singleton y)
+
 prop_empty1 = L.length L.empty == 0
 prop_empty2 = L.unpack L.empty == []
 
@@ -442,10 +649,23 @@
         l1 = fromIntegral (length splits)
         l2 = L.length (L.filter f xs)
 
+prop_splitWith_D f xs = (l1 == l2 || l1 == l2+1) &&
+        sum (map D.length splits) == D.length xs - l2
+  where splits = D.splitWith f xs
+        l1 = fromIntegral (length splits)
+        l2 = D.length (D.filter f xs)
+
+prop_splitWith_C f xs = (l1 == l2 || l1 == l2+1) &&
+        sum (map C.length splits) == C.length xs - l2
+  where splits = C.splitWith f xs
+        l1 = fromIntegral (length splits)
+        l2 = C.length (C.filter f xs)
+
 prop_joinsplit c xs = L.intercalate (pack [c]) (L.split c xs) == id xs
 
 prop_group xs       = group xs == (map unpack . L.group . pack) xs
 prop_groupBy  f xs  = groupBy f xs == (map unpack . L.groupBy f . pack) xs
+prop_groupBy_LC  f xs  = groupBy f xs == (map LC.unpack . LC.groupBy f .  LC.pack) xs
 
 -- prop_joinjoinByte xs ys c = L.joinWithByte c xs ys == L.join (L.singleton c) [xs,ys]
 
@@ -454,7 +674,18 @@
     forAll indices $ \i -> (xs !! i) == L.pack xs `L.index` (fromIntegral i)
   where indices = choose (0, length xs -1)
 
+prop_index_D xs =
+  not (null xs) ==>
+    forAll indices $ \i -> (xs !! i) == D.pack xs `D.index` (fromIntegral i)
+  where indices = choose (0, length xs -1)
+
+prop_index_C xs =
+  not (null xs) ==>
+    forAll indices $ \i -> (xs !! i) == C.pack xs `C.index` (fromIntegral i)
+  where indices = choose (0, length xs -1)
+
 prop_elemIndex xs c = (elemIndex c xs) == fmap fromIntegral (L.elemIndex c (pack xs))
+prop_elemIndexCL xs c = (elemIndex c xs) == (C.elemIndex c (C.pack xs))
 
 prop_elemIndices xs c = elemIndices c xs == map fromIntegral (L.elemIndices c (pack xs))
 
@@ -503,7 +734,12 @@
 
 prop_nil1BB = P.length P.empty == 0
 prop_nil2BB = P.unpack P.empty == []
+prop_nil1BB_monoid = P.length mempty == 0
+prop_nil2BB_monoid = P.unpack mempty == []
 
+prop_nil1LL_monoid = L.length mempty == 0
+prop_nil2LL_monoid = L.unpack mempty == []
+
 prop_tailSBB xs = not (P.null xs) ==> P.tail xs == P.pack (tail (P.unpack xs))
 
 prop_nullBB xs = null (P.unpack xs) == P.null xs
@@ -567,7 +803,11 @@
 prop_wordsSBB xs =
     C.words (C.pack xs) == map C.pack (words xs)
 
+prop_wordsLC xs =
+    LC.words (LC.pack xs) == map LC.pack (words xs)
+
 prop_unwordsSBB xss = C.unwords (map C.pack xss) == C.pack (unwords xss)
+prop_unwordsSLC xss = LC.unwords (map LC.pack xss) == LC.pack (unwords xss)
 
 prop_splitWithBB f xs = (l1 == l2 || l1 == l2+1) &&
         sum (map P.length splits) == P.length xs - l2
@@ -577,12 +817,23 @@
 
 prop_joinsplitBB c xs = P.intercalate (P.pack [c]) (P.split c xs) == xs
 
+prop_intercalatePL c x y =
+
+    P.intercalate (P.singleton c) (x : y : []) ==
+ --     intercalate (singleton c) (s1 : s2 : [])
+
+    P.pack (intercalate [c] [P.unpack x,P.unpack y])
+
 -- prop_linessplitBB xs =
 --     (not . C.null) xs ==>
 --     C.lines' xs == C.split '\n' xs
 
+-- false:
+{-
 prop_linessplit2BB xs =
+   (not . C.null) xs ==>
     C.lines xs == C.split '\n' xs ++ (if C.last xs == '\n' then [C.empty] else [])
+-}
 
 prop_splitsplitWithBB c xs = P.split c xs == P.splitWith (== c) xs
 
@@ -593,7 +844,7 @@
 prop_packunpackBB' s = (P.pack . P.unpack) s == id s
 
 prop_eq1BB xs      = xs            == (P.unpack . P.pack $ xs)
-prop_eq2BB xs      = xs == xs
+prop_eq2BB xs      = xs == (xs :: P.ByteString)
 prop_eq3BB xs ys   = (xs == ys) == (P.unpack xs == P.unpack ys)
 
 prop_compare1BB xs  = (P.pack xs         `compare` P.pack xs) == EQ
@@ -634,6 +885,14 @@
 prop_append2BB xs ys = (xs ++ ys) == (P.unpack $ P.pack xs `P.append` P.pack ys)
 prop_append3BB xs ys = P.append xs ys == P.pack (P.unpack xs ++ P.unpack ys)
 
+prop_append1BB_monoid xs    = (xs ++ xs) == (P.unpack $ P.pack xs `mappend` P.pack xs)
+prop_append2BB_monoid xs ys = (xs ++ ys) == (P.unpack $ P.pack xs `mappend` P.pack ys)
+prop_append3BB_monoid xs ys = mappend xs ys == P.pack (P.unpack xs ++ P.unpack ys)
+
+prop_append1LL_monoid xs    = (xs ++ xs) == (L.unpack $ L.pack xs `mappend` L.pack xs)
+prop_append2LL_monoid xs ys = (xs ++ ys) == (L.unpack $ L.pack xs `mappend` L.pack ys)
+prop_append3LL_monoid xs ys = mappend xs ys == L.pack (L.unpack xs ++ L.unpack ys)
+
 prop_map1BB f xs   = P.map f (P.pack xs)    == P.pack (map f xs)
 prop_map2BB f g xs = P.map f (P.map g xs) == P.map (f . g) xs
 prop_map3BB f xs   = map f xs == (P.unpack . P.map f .  P.pack) xs
@@ -689,6 +948,10 @@
 
 prop_dropWhileBB xs a = (dropWhile (/= a) xs) == (P.unpack . (P.dropWhile (/= a)) . P.pack) xs
 
+prop_dropWhileCC_isSpace xs =
+        (dropWhile isSpace xs) ==
+       (C.unpack .  (C.dropWhile isSpace) . C.pack) xs
+
 prop_takeBB xs = (take 10 xs) == (P.unpack . (P.take 10) . P.pack) xs
 
 prop_dropBB xs = (drop 10 xs) == (P.unpack . (P.drop 10) . P.pack) xs
@@ -716,6 +979,14 @@
 prop_concat2BB xs = (concat [xs,[]]) == (P.unpack $ P.concat [P.pack xs, P.pack []])
 prop_concatBB xss = P.concat (map P.pack xss) == P.pack (concat xss)
 
+prop_concat1BB_monoid xs = (concat [xs,xs]) == (P.unpack $ mconcat [P.pack xs, P.pack xs])
+prop_concat2BB_monoid xs = (concat [xs,[]]) == (P.unpack $ mconcat [P.pack xs, P.pack []])
+prop_concatBB_monoid xss = mconcat (map P.pack xss) == P.pack (concat xss)
+
+prop_concat1LL_monoid xs = (concat [xs,xs]) == (L.unpack $ mconcat [L.pack xs, L.pack xs])
+prop_concat2LL_monoid xs = (concat [xs,[]]) == (L.unpack $ mconcat [L.pack xs, L.pack []])
+prop_concatLL_monoid xss = mconcat (map L.pack xss) == L.pack (concat xss)
+
 prop_concatMapBB xs = C.concatMap C.singleton xs == (C.pack . concatMap (:[]) . C.unpack) xs
 
 prop_anyBB xs a = (any (== a) xs) == (P.any (== a) (P.pack xs))
@@ -724,6 +995,7 @@
 prop_linesBB xs = (lines xs) == ((map C.unpack) . C.lines . C.pack) xs
 
 prop_unlinesBB xs = (unlines.lines) xs == (C.unpack. C.unlines . C.lines .C.pack) xs
+prop_unlinesLC xs = (unlines.lines) xs == (LC.unpack. LC.unlines .  LC.lines .LC.pack) xs
 
 prop_wordsBB xs =
     (words xs) == ((map C.unpack) . C.words . C.pack) xs
@@ -735,7 +1007,9 @@
 prop_groupBB xs   = group xs == (map P.unpack . P.group . P.pack) xs
 
 prop_groupByBB  xs = groupBy (==) xs == (map P.unpack . P.groupBy (==) . P.pack) xs
+prop_groupByCC  xs = groupBy (==) xs == (map C.unpack . C.groupBy (==) . C.pack) xs
 prop_groupBy1BB xs = groupBy (/=) xs == (map P.unpack . P.groupBy (/=) . P.pack) xs
+prop_groupBy1CC xs = groupBy (/=) xs == (map C.unpack . C.groupBy (/=) . C.pack) xs
 
 prop_joinBB xs ys = (concat . (intersperse ys) . lines) xs ==
                (C.unpack $ C.intercalate (C.pack ys) (C.lines (C.pack xs)))
@@ -752,6 +1026,11 @@
                                 Nothing -> Nothing
                                 Just i  -> Just (length xs -1 -i))
 
+prop_elemIndexEnd1CC c xs = (C.elemIndexEnd c (C.pack xs)) ==
+                           (case C.elemIndex c (C.pack (reverse xs)) of
+                                Nothing -> Nothing
+                                Just i  -> Just (length xs -1 -i))
+
 prop_elemIndexEnd2BB c xs = (P.elemIndexEnd c (P.pack xs)) ==
                            ((-) (length xs - 1) `fmap` P.elemIndex c (P.pack $ reverse xs))
 
@@ -776,7 +1055,7 @@
 
 prop_intersperseBB c xs = (intersperse c xs) == (P.unpack $ P.intersperse c (P.pack xs))
 
-prop_transposeBB xs = (transpose xs) == ((map P.unpack) . P.transpose .  (map P.pack)) xs
+-- prop_transposeBB xs = (transpose xs) == ((map P.unpack) . P.transpose .  (map P.pack)) xs
 
 prop_maximumBB xs = (not (null xs)) ==> (maximum xs) == (P.maximum ( P.pack xs ))
 prop_minimumBB xs = (not (null xs)) ==> (minimum xs) == (P.minimum ( P.pack xs ))
@@ -794,6 +1073,7 @@
         (let (x,y) = C.span (not.isSpace) (C.reverse (C.pack xs)) in (C.reverse y,C.reverse x))
 
 prop_breakEndBB p xs = P.breakEnd (not.p) xs == P.spanEnd p xs
+prop_breakEndCC p xs = C.breakEnd (not.p) xs == C.spanEnd p xs
 
 {-
 prop_breakCharBB c xs =
@@ -821,8 +1101,10 @@
 
 prop_prefixBB xs ys = isPrefixOf xs ys == (P.pack xs `P.isPrefixOf` P.pack ys)
 prop_suffixBB xs ys = isSuffixOf xs ys == (P.pack xs `P.isSuffixOf` P.pack ys)
+prop_suffixLL xs ys = isSuffixOf xs ys == (L.pack xs `L.isSuffixOf` L.pack ys)
 
 prop_copyBB xs = let p = P.pack xs in P.copy p == p
+prop_copyLL xs = let p = L.pack xs in L.copy p == p
 
 prop_initsBB xs = inits xs == map P.unpack (P.inits (P.pack xs))
 
@@ -841,6 +1123,35 @@
     naive_findSubstrings :: String -> String -> [Int]
     naive_findSubstrings p s = [x | x <- [0..length s], p `isPrefixOf` drop x s]
 
+prop_findSubstringBB s x l
+    = C.findSubstring (C.pack p) (C.pack s) == naive_findSubstring p s
+  where
+    _ = l :: Int
+    _ = x :: Int
+
+    -- we look for some random substring of the test string
+    p = take (model l) $ drop (model x) s
+
+    -- naive reference implementation
+    naive_findSubstring :: String -> String -> Maybe Int
+    naive_findSubstring p s = listToMaybe [x | x <- [0..length s], p `isPrefixOf` drop x s]
+
+-- correspondance between break and breakSubstring
+prop_breakSubstringBB c l
+    = P.break (== c) l == P.breakSubstring (P.singleton c) l
+
+prop_breakSubstring_isInfixOf s l
+    = P.isInfixOf s l == if P.null s then True
+                                     else case P.breakSubstring s l of
+                                            (x,y) | P.null y  -> False
+                                                  | otherwise -> True
+
+prop_breakSubstring_findSubstring s l
+    = P.findSubstring s l == if P.null s then Just 0
+                                       else case P.breakSubstring s l of
+                                            (x,y) | P.null y  -> Nothing
+                                                  | otherwise -> Just (P.length x)
+
 prop_replicate1BB n c = P.unpack (P.replicate n c) == replicate n c
 prop_replicate2BB n c = P.replicate n c == fst (P.unfoldrN n (\u -> Just (u,u)) c)
 
@@ -849,6 +1160,9 @@
 prop_readintBB n = (fst . fromJust . C.readInt . C.pack . show) n == (n :: Int)
 prop_readintLL n = (fst . fromJust . D.readInt . D.pack . show) n == (n :: Int)
 
+prop_readBB x = (read . show) x == (x :: P.ByteString)
+prop_readLL x = (read . show) x == (x :: L.ByteString)
+
 prop_readint2BB s =
     let s' = filter (\c -> c `notElem` ['0'..'9']) s
     in C.readInt (C.pack s') == Nothing
@@ -870,9 +1184,12 @@
 -- prop_joinjoinpathBB xs ys c = C.joinWithChar c xs ys == C.join (C.singleton c) [xs,ys]
 
 prop_zipBB  xs ys = zip xs ys == P.zip (P.pack xs) (P.pack ys)
+prop_zipLC  xs ys = zip xs ys == LC.zip (LC.pack xs) (LC.pack ys)
 prop_zip1BB xs ys = P.zip xs ys == zip (P.unpack xs) (P.unpack ys)
 
 prop_zipWithBB xs ys = P.zipWith (,) xs ys == P.zip xs ys
+prop_zipWithCC xs ys = C.zipWith (,) xs ys == C.zip xs ys
+prop_zipWithLC xs ys = LC.zipWith (,) xs ys == LC.zip xs ys
 -- prop_zipWith'BB xs ys = P.pack (P.zipWith (+) xs ys) == P.zipWith' (+) xs ys
 
 prop_unzipBB x = let (xs,ys) = unzip x in (P.pack xs, P.pack ys) == P.unzip x
@@ -882,6 +1199,7 @@
 -- And check fusion RULES.
 --
 
+{-
 prop_lazylooploop em1 em2 start1 start2 arr =
     loopL em2 start2 (loopArr (loopL em1 start1 arr))             ==
     loopSndAcc (loopL (em1 `fuseEFL` em2) (start1 :*: start2) arr)
@@ -1075,6 +1393,8 @@
   where _ = acc1 :: Int
 -}
 
+-}
+
 -- prop_zipwith_spec f p q =
 --   P.pack (P.zipWith f p q) == P.zipWith' f p q
 --   where _ = f :: Word8 -> Word8 -> Word8
@@ -1088,17 +1408,201 @@
 -- prop_span_spec x s =
 --     P.span ((==) x) s == P.spanByte x s
 
+------------------------------------------------------------------------
 
+-- Test IsString
+prop_isstring x = C.unpack (fromString x :: C.ByteString) == x
+prop_isstring_lc x = LC.unpack (fromString x :: LC.ByteString) == x
+
 ------------------------------------------------------------------------
+-- Unsafe functions
+
+-- Test unsafePackAddress
+prop_unsafePackAddress x = unsafePerformIO $ do
+        let (p,_,_) = P.toForeignPtr (x `P.snoc` 0)
+        y <- withForeignPtr p $ \(Ptr addr) ->
+            P.unsafePackAddress addr
+        return (y == x)
+
+-- Test unsafePackAddressLen
+prop_unsafePackAddressLen x = unsafePerformIO $ do
+        let i = P.length x
+            (p,_,_) = P.toForeignPtr (x `P.snoc` 0)
+        y <- withForeignPtr p $ \(Ptr addr) ->
+            P.unsafePackAddressLen i addr
+        return (y == x)
+
+prop_unsafeUseAsCString x = unsafePerformIO $ do
+        let n = P.length x
+        y <- P.unsafeUseAsCString x $ \cstr ->
+                    sequence [ do a <- peekElemOff cstr i
+                                  let b = x `P.index` i
+                                  return (a == fromIntegral b)
+                             | i <- [0.. n-1]     ]
+        return (and y)
+
+prop_unsafeUseAsCStringLen x = unsafePerformIO $ do
+        let n = P.length x
+        y <- P.unsafeUseAsCStringLen x $ \(cstr,_) ->
+                    sequence [ do a <- peekElemOff cstr i
+                                  let b = x `P.index` i
+                                  return (a == fromIntegral b)
+                             | i <- [0.. n-1]     ]
+        return (and y)
+
+prop_internal_invariant x = LP.invariant x
+
+prop_useAsCString x = unsafePerformIO $ do
+        let n = P.length x
+        y <- P.useAsCString x $ \cstr ->
+                    sequence [ do a <- peekElemOff cstr i
+                                  let b = x `P.index` i
+                                  return (a == fromIntegral b)
+                             | i <- [0.. n-1]     ]
+        return (and y)
+
+prop_packCString x = unsafePerformIO $ do
+        y <- P.useAsCString x $ P.unsafePackCString
+        return (y == x)
+
+prop_packCString_safe x = unsafePerformIO $ do
+        y <- P.useAsCString x $ P.packCString
+        return (y == x)
+
+prop_packCStringLen x = unsafePerformIO $ do
+        y <- P.useAsCStringLen x $ P.unsafePackCStringLen
+        return (y == x && P.length y == P.length x)
+
+prop_packCStringLen_safe x = unsafePerformIO $ do
+        y <- P.useAsCStringLen x $ P.packCStringLen
+        return (y == x && P.length y == P.length x)
+
+prop_packMallocCString x = unsafePerformIO $ do
+
+         let (fp,_,_) = P.toForeignPtr x
+         ptr <- mallocArray0 (P.length x) :: IO (Ptr Word8)
+         forM_ [0 .. P.length x] $ \n -> pokeElemOff ptr n 0
+         withForeignPtr fp $ \qtr -> copyArray ptr qtr (P.length x)
+         y   <- P.unsafePackMallocCString (castPtr ptr)
+
+         let !z = y == x
+         free ptr `seq` return z
+
+prop_unsafeFinalize    x = unsafePerformIO $ do
+        x <- P.unsafeFinalize x
+        return (x == ())
+
+prop_packCStringFinaliser x = unsafePerformIO $ do
+        y <- P.useAsCString x $ \cstr -> P.unsafePackCStringFinalizer (castPtr cstr) (P.length x) (return ())
+        return (y == x)
+
+prop_show x = show x == show (C.unpack x)
+
+prop_fromForeignPtr x = (let (a,b,c) = (P.toForeignPtr x)
+                                in P.fromForeignPtr a b c) == x
+
+------------------------------------------------------------------------
+-- IO
+
+prop_read_write_file_P x = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do P.writeFile f x)
+        (const $ do removeFile f)
+        (const $ do y <- P.readFile f
+                    return (x==y))
+
+prop_read_write_file_C x = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do C.writeFile f x)
+        (const $ do removeFile f)
+        (const $ do y <- C.readFile f
+                    return (x==y))
+
+prop_read_write_file_L x = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do L.writeFile f x)
+        (const $ do removeFile f)
+        (const $ do y <- L.readFile f
+                    return (x==y))
+
+prop_read_write_file_D x = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do D.writeFile f x)
+        (const $ do removeFile f)
+        (const $ do y <- D.readFile f
+                    return (x==y))
+
+------------------------------------------------------------------------
+
+prop_append_file_P x y = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do P.writeFile f x
+            P.appendFile f y)
+        (const $ do removeFile f)
+        (const $ do z <- P.readFile f
+                    return (z==(x `P.append` y)))
+
+prop_append_file_C x y = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do C.writeFile f x
+            C.appendFile f y)
+        (const $ do removeFile f)
+        (const $ do z <- C.readFile f
+                    return (z==(x `C.append` y)))
+
+prop_append_file_L x y = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do L.writeFile f x
+            L.appendFile f y)
+        (const $ do removeFile f)
+        (const $ do z <- L.readFile f
+                    return (z==(x `L.append` y)))
+
+prop_append_file_D x y = unsafePerformIO $ do
+    tid <- myThreadId
+    let f = "qc-test-"++show tid
+    bracket
+        (do D.writeFile f x
+            D.appendFile f y)
+        (const $ do removeFile f)
+        (const $ do z <- D.readFile f
+                    return (z==(x `D.append` y)))
+
+prop_packAddress = C.pack "this is a test" 
+            ==
+                   C.pack "this is a test" 
+
+prop_isSpaceWord8 (w :: Word8) = isSpace c == P.isSpaceChar8 c
+   where c = chr (fromIntegral w)
+ 
+
+------------------------------------------------------------------------
 -- The entry point
 
+main :: IO ()
 main = run tests
 
-run :: [(String, Int -> IO ())] -> IO ()
+run :: [(String, Int -> IO (Bool,Int))] -> IO ()
 run tests = do
     x <- getArgs
     let n = if null x then 100 else read . head $ x
-    mapM_ (\(s,a) -> printf "%-25s: " s >> a n) tests
+    (results, passed) <- liftM unzip $ mapM (\(s,a) -> printf "%-40s: " s >> a n) tests
+    printf "Passed %d tests!\n" (sum passed)
+    when (not . and $ results) $ fail "Not all tests passed!"
 
 --
 -- And now a list of all the properties to test.
@@ -1106,14 +1610,50 @@
 
 tests = misc_tests
      ++ bl_tests
+     ++ cc_tests
      ++ bp_tests
      ++ pl_tests
      ++ bb_tests
      ++ ll_tests
-     ++ fusion_tests
+     ++ io_tests
+     ++ rules
 
+--
+-- 'morally sound' IO
+--
+io_tests =
+    [("readFile.writeFile", mytest prop_read_write_file_P)
+    ,("readFile.writeFile", mytest prop_read_write_file_C)
+    ,("readFile.writeFile", mytest prop_read_write_file_L)
+    ,("readFile.writeFile", mytest prop_read_write_file_D)
+
+    ,("appendFile        ", mytest prop_append_file_P)
+    ,("appendFile        ", mytest prop_append_file_C)
+    ,("appendFile        ", mytest prop_append_file_L)
+    ,("appendFile        ", mytest prop_append_file_D)
+
+    ,("packAddress       ", mytest prop_packAddress)
+
+    ]
+
 misc_tests =
-    [("invariant",          mytest prop_invariant)]
+    [("invariant",              mytest prop_invariant)
+    ,("unsafe pack address",    mytest prop_unsafePackAddress)
+    ,("unsafe pack address len",mytest prop_unsafePackAddressLen)
+    ,("unsafeUseAsCString",     mytest prop_unsafeUseAsCString)
+    ,("unsafeUseAsCStringLen",  mytest prop_unsafeUseAsCStringLen)
+    ,("useAsCString",           mytest prop_useAsCString)
+    ,("packCString",            mytest prop_packCString)
+    ,("packCString safe",       mytest prop_packCString_safe)
+    ,("packCStringLen",         mytest prop_packCStringLen)
+    ,("packCStringLen safe",    mytest prop_packCStringLen_safe)
+    ,("packCStringFinaliser",   mytest prop_packCStringFinaliser)
+    ,("packMallocString",       mytest prop_packMallocCString)
+    ,("unsafeFinalise",         mytest prop_unsafeFinalize)
+    ,("invariant",              mytest prop_internal_invariant)
+    ,("show",                   mytest prop_show)
+    ,("fromForeignPtr",         mytest prop_fromForeignPtr)
+    ]
 
 ------------------------------------------------------------------------
 -- ByteString.Lazy <=> List
@@ -1138,7 +1678,16 @@
     ,("foldr1",      mytest prop_foldr1BL)
     ,("mapAccumL",   mytest prop_mapAccumLBL)
     ,("mapAccumR",   mytest prop_mapAccumRBL)
+    ,("mapAccumR",   mytest prop_mapAccumRDL)
+    ,("mapAccumR",   mytest prop_mapAccumRCC)
     ,("unfoldr",     mytest prop_unfoldrBL)
+    ,("unfoldr",     mytest prop_unfoldrLC)
+    ,("unfoldr",     mytest prop_cycleLC)
+    ,("iterate",     mytest prop_iterateLC)
+    ,("iterate",     mytest prop_iterateLC_2)
+    ,("iterate",     mytest prop_iterateL)
+    ,("repeat",      mytest prop_repeatLC)
+    ,("repeat",      mytest prop_repeatL)
     ,("head",        mytest prop_headBL)
     ,("init",        mytest prop_initBL)
     ,("isPrefixOf",  mytest prop_isPrefixOfBL)
@@ -1174,6 +1723,65 @@
 ------------------------------------------------------------------------
 -- ByteString.Lazy <=> ByteString
 
+cc_tests =
+    [("prop_concatCC", mytest prop_concatCC)
+    ,("prop_nullCC", mytest prop_nullCC)
+    ,("prop_reverseCC", mytest prop_reverseCC)
+    ,("prop_transposeCC", mytest prop_transposeCC)
+    ,("prop_groupCC", mytest prop_groupCC)
+    ,("prop_initsCC", mytest prop_initsCC)
+    ,("prop_tailsCC", mytest prop_tailsCC)
+    ,("prop_allCC", mytest prop_allCC)
+    ,("prop_anyCC", mytest prop_anyCC)
+    ,("prop_appendCC", mytest prop_appendCC)
+    ,("prop_breakCC", mytest prop_breakCC)
+    ,("prop_concatMapCC", mytest prop_concatMapCC)
+    ,("prop_consCC", mytest prop_consCC)
+    ,("prop_unconsCC", mytest prop_unconsCC)
+    ,("prop_countCC", mytest prop_countCC)
+    ,("prop_dropCC", mytest prop_dropCC)
+    ,("prop_dropWhileCC", mytest prop_dropWhileCC)
+    ,("prop_filterCC", mytest prop_filterCC)
+    ,("prop_findCC", mytest prop_findCC)
+    ,("prop_findIndexCC", mytest prop_findIndexCC)
+    ,("prop_findIndicesCC", mytest prop_findIndicesCC)
+    ,("prop_isPrefixOfCC", mytest prop_isPrefixOfCC)
+    ,("prop_mapCC", mytest prop_mapCC)
+    ,("prop_replicateCC", mytest prop_replicateCC)
+    ,("prop_snocCC", mytest prop_snocCC)
+    ,("prop_spanCC", mytest prop_spanCC)
+    ,("prop_splitCC", mytest prop_splitCC)
+    ,("prop_splitAtCC", mytest prop_splitAtCC)
+    ,("prop_takeCC", mytest prop_takeCC)
+    ,("prop_takeWhileCC", mytest prop_takeWhileCC)
+    ,("prop_elemCC", mytest prop_elemCC)
+    ,("prop_notElemCC", mytest prop_notElemCC)
+    ,("prop_elemIndexCC", mytest prop_elemIndexCC)
+    ,("prop_elemIndicesCC", mytest prop_elemIndicesCC)
+    ,("prop_lengthCC", mytest prop_lengthCC)
+    ,("prop_headCC", mytest prop_headCC)
+    ,("prop_initCC", mytest prop_initCC)
+    ,("prop_lastCC", mytest prop_lastCC)
+    ,("prop_maximumCC", mytest prop_maximumCC)
+    ,("prop_minimumCC", mytest prop_minimumCC)
+    ,("prop_tailCC", mytest prop_tailCC)
+    ,("prop_foldl1CC", mytest prop_foldl1CC)
+    ,("prop_foldl1CC'", mytest prop_foldl1CC')
+    ,("prop_foldr1CC", mytest prop_foldr1CC)
+    ,("prop_foldr1CC'", mytest prop_foldr1CC')
+    ,("prop_scanlCC", mytest prop_scanlCC)
+    ,("prop_intersperseCC", mytest prop_intersperseCC)
+
+    ,("prop_foldlCC", mytest prop_foldlCC)
+    ,("prop_foldlCC'", mytest prop_foldlCC')
+    ,("prop_foldrCC", mytest prop_foldrCC)
+    ,("prop_foldrCC'", mytest prop_foldrCC')
+    ,("prop_mapAccumLCC", mytest prop_mapAccumLCC)
+--    ,("prop_mapIndexedCC", mytest prop_mapIndexedCC)
+--    ,("prop_mapIndexedPL", mytest prop_mapIndexedPL)
+
+    ]
+
 bp_tests =
     [("all",         mytest prop_allBP)
     ,("any",         mytest prop_anyBP)
@@ -1181,6 +1789,9 @@
     ,("compare",     mytest prop_compareBP)
     ,("concat",      mytest prop_concatBP)
     ,("cons",        mytest prop_consBP)
+    ,("cons'",       mytest prop_consBP')
+    ,("cons'",       mytest prop_consLP')
+    ,("uncons",      mytest prop_unconsBP)
     ,("eq",          mytest prop_eqBP)
     ,("filter",      mytest prop_filterBP)
     ,("find",        mytest prop_findBP)
@@ -1191,9 +1802,14 @@
     ,("foldl1",      mytest prop_foldl1BP)
     ,("foldl1'",     mytest prop_foldl1BP')
     ,("foldr",       mytest prop_foldrBP)
+    ,("foldr'",       mytest prop_foldrBP')
     ,("foldr1",      mytest prop_foldr1BP)
+    ,("foldr1'",      mytest prop_foldr1BP')
     ,("mapAccumL",   mytest prop_mapAccumLBP)
+--  ,("mapAccumL",   mytest prop_mapAccumL_mapIndexedBP)
     ,("unfoldr",     mytest prop_unfoldrBP)
+    ,("unfoldr 2",   mytest prop_unfoldr2BP)
+    ,("unfoldr 2",   mytest prop_unfoldr2CP)
     ,("head",        mytest prop_headBP)
     ,("init",        mytest prop_initBP)
     ,("isPrefixOf",  mytest prop_isPrefixOfBP)
@@ -1228,6 +1844,7 @@
     ,("notElem",     mytest prop_notElemBP)
     ,("elemIndex",   mytest prop_elemIndexBP)
     ,("elemIndices", mytest prop_elemIndicesBP)
+    ,("intersperse", mytest prop_intersperseBP)
     ,("concatMap",   mytest prop_concatMapBP)
     ]
 
@@ -1243,6 +1860,10 @@
     ,("cons",        mytest prop_consPL)
     ,("eq",          mytest prop_eqPL)
     ,("filter",      mytest prop_filterPL)
+    ,("filter rules",mytest prop_filterPL_rule)
+    ,("filter rules",mytest prop_filterLC_rule)
+    ,("partition",   mytest prop_partitionPL)
+    ,("partition",   mytest prop_partitionLL)
     ,("find",        mytest prop_findPL)
     ,("findIndex",   mytest prop_findIndexPL)
     ,("findIndices", mytest prop_findIndicesPL)
@@ -1257,8 +1878,11 @@
     ,("unfoldr",     mytest prop_unfoldrPL)
     ,("scanl",       mytest prop_scanlPL)
     ,("scanl1",      mytest prop_scanl1PL)
+    ,("scanl1",      mytest prop_scanl1CL)
+    ,("scanr",      mytest prop_scanrCL)
     ,("scanr",       mytest prop_scanrPL)
     ,("scanr1",      mytest prop_scanr1PL)
+    ,("scanr1",      mytest prop_scanr1CL)
     ,("head",        mytest prop_headPL)
     ,("init",        mytest prop_initPL)
     ,("last",        mytest prop_lastPL)
@@ -1266,11 +1890,18 @@
     ,("minimum",     mytest prop_minimumPL)
     ,("tail",        mytest prop_tailPL)
     ,("zip",         mytest prop_zipPL)
+    ,("zip",         mytest prop_zipLL)
+    ,("zip",         mytest prop_zipCL)
     ,("unzip",       mytest prop_unzipPL)
+    ,("unzip",       mytest prop_unzipLL)
+    ,("unzip",       mytest prop_unzipCL)
     ,("zipWith",          mytest prop_zipWithPL)
+--  ,("zipWith",          mytest prop_zipWithCL)
+    ,("zipWith rules",   mytest prop_zipWithPL_rules)
 --     ,("zipWith/zipWith'", mytest prop_zipWithPL')
 
     ,("isPrefixOf",  mytest prop_isPrefixOfPL)
+    ,("isInfixOf",   mytest prop_isInfixOfPL)
     ,("length",      mytest prop_lengthPL)
     ,("map",         mytest prop_mapPL)
     ,("null",        mytest prop_nullPL)
@@ -1290,10 +1921,13 @@
     ,("tails",       mytest prop_tailsPL)
     ,("elem",        mytest prop_elemPL)
     ,("notElem",     mytest prop_notElemPL)
-    ,("lines",       mytest prop_linesBL)
+    ,("lines",       mytest prop_linesPL)
     ,("elemIndex",   mytest prop_elemIndexPL)
+    ,("elemIndex",   mytest prop_elemIndexCL)
     ,("elemIndices", mytest prop_elemIndicesPL)
     ,("concatMap",   mytest prop_concatMapPL)
+    ,("IsString",    mytest prop_isstring)
+    ,("IsString LC",    mytest prop_isstring_lc)
     ]
 
 ------------------------------------------------------------------------
@@ -1305,7 +1939,7 @@
     ,    ("pack/unpack",    mytest prop_packunpackBB)
     ,    ("unpack/pack",    mytest prop_packunpackBB')
     ,    ("eq 1",           mytest prop_eq1BB)
-    ,    ("eq 2",           mytest prop_eq3BB)
+    ,    ("eq 2",           mytest prop_eq2BB)
     ,    ("eq 3",           mytest prop_eq3BB)
     ,    ("compare 1",      mytest prop_compare1BB)
     ,    ("compare 2",      mytest prop_compare2BB)
@@ -1314,9 +1948,15 @@
     ,    ("compare 5",      mytest prop_compare5BB)
     ,    ("compare 6",      mytest prop_compare6BB)
     ,    ("compare 7",      mytest prop_compare7BB)
+    ,    ("compare 7",      mytest prop_compare7LL)
     ,    ("compare 8",      mytest prop_compare8BB)
     ,    ("empty 1",        mytest prop_nil1BB)
     ,    ("empty 2",        mytest prop_nil2BB)
+    ,    ("empty 1 monoid", mytest prop_nil1LL_monoid)
+    ,    ("empty 2 monoid", mytest prop_nil2LL_monoid)
+    ,    ("empty 1 monoid", mytest prop_nil1BB_monoid)
+    ,    ("empty 2 monoid", mytest prop_nil2BB_monoid)
+
     ,    ("null",           mytest prop_nullBB)
     ,    ("length 1",       mytest prop_lengthBB)
     ,    ("length 2",       mytest prop_lengthSBB)
@@ -1336,13 +1976,17 @@
     ,    ("append 1",       mytest prop_append1BB)
     ,    ("append 2",       mytest prop_append2BB)
     ,    ("append 3",       mytest prop_append3BB)
+    ,    ("mappend 1",       mytest prop_append1BB_monoid)
+    ,    ("mappend 2",       mytest prop_append2BB_monoid)
+    ,    ("mappend 3",       mytest prop_append3BB_monoid)
+
     ,    ("map 1",          mytest prop_map1BB)
     ,    ("map 2",          mytest prop_map2BB)
     ,    ("map 3",          mytest prop_map3BB)
     ,    ("filter1",        mytest prop_filter1BB)
     ,    ("filter2",        mytest prop_filter2BB)
-    ,    ("map fusion",     mytest prop_mapfusionBB)
-    ,    ("filter fusion",  mytest prop_filterfusionBB)
+--  ,    ("map fusion",     mytest prop_mapfusionBB)
+--  ,    ("filter fusion",  mytest prop_filterfusionBB)
     ,    ("reverse 1",      mytest prop_reverse1BB)
     ,    ("reverse 2",      mytest prop_reverse2BB)
     ,    ("reverse 3",      mytest prop_reverse3BB)
@@ -1363,21 +2007,35 @@
     ,    ("drop",           mytest prop_dropBB)
     ,    ("takeWhile",      mytest prop_takeWhileBB)
     ,    ("dropWhile",      mytest prop_dropWhileBB)
+    ,    ("dropWhile",      mytest prop_dropWhileCC_isSpace)
     ,    ("splitAt",        mytest prop_splitAtBB)
     ,    ("span",           mytest prop_spanBB)
     ,    ("break",          mytest prop_breakBB)
     ,    ("elem",           mytest prop_elemBB)
     ,    ("notElem",        mytest prop_notElemBB)
+
     ,    ("concat 1",       mytest prop_concat1BB)
     ,    ("concat 2",       mytest prop_concat2BB)
     ,    ("concat 3",       mytest prop_concatBB)
+    ,    ("mconcat 1",       mytest prop_concat1BB_monoid)
+    ,    ("mconcat 2",       mytest prop_concat2BB_monoid)
+    ,    ("mconcat 3",       mytest prop_concatBB_monoid)
+
+    ,    ("mconcat 1",       mytest prop_concat1LL_monoid)
+    ,    ("mconcat 2",       mytest prop_concat2LL_monoid)
+    ,    ("mconcat 3",       mytest prop_concatLL_monoid)
+
     ,    ("lines",          mytest prop_linesBB)
     ,    ("unlines",        mytest prop_unlinesBB)
+    ,    ("unlines",        mytest prop_unlinesLC)
     ,    ("words",          mytest prop_wordsBB)
+    ,    ("words",          mytest prop_wordsLC)
     ,    ("unwords",        mytest prop_unwordsBB)
     ,    ("group",          mytest prop_groupBB)
     ,    ("groupBy",        mytest prop_groupByBB)
+    ,    ("groupBy",        mytest prop_groupByCC)
     ,    ("groupBy 1",      mytest prop_groupBy1BB)
+    ,    ("groupBy 1",      mytest prop_groupBy1CC)
     ,    ("join",           mytest prop_joinBB)
     ,    ("elemIndex 1",    mytest prop_elemIndex1BB)
     ,    ("elemIndex 2",    mytest prop_elemIndex2BB)
@@ -1401,7 +2059,9 @@
 --  ,    ("dropSpace",      mytest prop_dropSpaceBB)
     ,    ("spanEnd",        mytest prop_spanEndBB)
     ,    ("breakEnd",       mytest prop_breakEndBB)
+    ,    ("breakEnd",       mytest prop_breakEndCC)
     ,    ("elemIndexEnd 1",mytest prop_elemIndexEnd1BB)
+    ,    ("elemIndexEnd 1",mytest prop_elemIndexEnd1CC)
     ,    ("elemIndexEnd 2",mytest prop_elemIndexEnd2BB)
 --  ,    ("words'",         mytest prop_wordsBB')
 --     ,    ("lines'",         mytest prop_linesBB')
@@ -1409,10 +2069,17 @@
     ,    ("unfoldr",        mytest prop_unfoldrBB)
     ,    ("prefix",         mytest prop_prefixBB)
     ,    ("suffix",         mytest prop_suffixBB)
+    ,    ("suffix",         mytest prop_suffixLL)
     ,    ("copy",           mytest prop_copyBB)
+    ,    ("copy",           mytest prop_copyLL)
     ,    ("inits",          mytest prop_initsBB)
     ,    ("tails",          mytest prop_tailsBB)
     ,    ("findSubstrings ",mytest prop_findSubstringsBB)
+    ,    ("findSubstring ",mytest prop_findSubstringBB)
+    ,    ("breakSubstring 1",mytest prop_breakSubstringBB)
+    ,    ("breakSubstring 2",mytest prop_breakSubstring_findSubstring)
+    ,    ("breakSubstring 3",mytest prop_breakSubstring_isInfixOf)
+
     ,    ("replicate1",     mytest prop_replicate1BB)
     ,    ("replicate2",     mytest prop_replicate2BB)
     ,    ("replicate3",     mytest prop_replicate3BB)
@@ -1420,8 +2087,14 @@
     ,    ("readInt 2",      mytest prop_readint2BB)
     ,    ("readInteger",    mytest prop_readintegerBB)
     ,    ("readInteger 2",  mytest prop_readinteger2BB)
+    ,    ("read",  mytest prop_readLL)
+    ,    ("read",  mytest prop_readBB)
     ,    ("Lazy.readInt",   mytest prop_readintLL)
+    ,    ("Lazy.readInt",   mytest prop_readintLL)
     ,    ("Lazy.readInteger", mytest prop_readintegerLL)
+    ,    ("mconcat 1",       mytest prop_append1LL_monoid)
+    ,    ("mconcat 2",       mytest prop_append2LL_monoid)
+    ,    ("mconcat 3",       mytest prop_append3LL_monoid)
 --  ,    ("filterChar1",    mytest prop_filterChar1BB)
 --  ,    ("filterChar2",    mytest prop_filterChar2BB)
 --  ,    ("filterChar3",    mytest prop_filterChar3BB)
@@ -1447,17 +2120,22 @@
     ,    ("unlines ",       mytest prop_unlinesSBB)
     ,    ("words ",         mytest prop_wordsSBB)
     ,    ("unwords ",       mytest prop_unwordsSBB)
+    ,    ("unwords ",       mytest prop_unwordsSLC)
 --     ,    ("wordstokens",    mytest prop_wordstokensBB)
     ,    ("splitWith",      mytest prop_splitWithBB)
     ,    ("joinsplit",      mytest prop_joinsplitBB)
+    ,    ("intercalate",    mytest prop_intercalatePL)
 --     ,    ("lineIndices",    mytest prop_lineIndices1BB)
     ,    ("count",          mytest prop_countBB)
---  ,    ("linessplit",     mytest prop_linessplitBB)
+--  ,    ("linessplit",     mytest prop_linessplit2BB)
     ,    ("splitsplitWith", mytest prop_splitsplitWithBB)
 --  ,    ("joinjoinpath",   mytest prop_joinjoinpathBB)
     ,    ("zip",            mytest prop_zipBB)
+    ,    ("zip",            mytest prop_zipLC)
     ,    ("zip1",           mytest prop_zip1BB)
     ,    ("zipWith",        mytest prop_zipWithBB)
+    ,    ("zipWith",        mytest prop_zipWithCC)
+    ,    ("zipWith",        mytest prop_zipWithLC)
 --     ,    ("zipWith'",       mytest prop_zipWith'BB)
     ,    ("unzip",          mytest prop_unzipBB)
     ,    ("concatMap",      mytest prop_concatMapBB)
@@ -1469,6 +2147,7 @@
 ------------------------------------------------------------------------
 -- Fusion rules
 
+{-
 fusion_tests =
 -- v1 fusion
     [    ("lazy loop/loop fusion", mytest prop_lazylooploop)
@@ -1512,7 +2191,9 @@
 --  ,("zipwith/spec",                  mytest prop_zipwith_spec)
     ]
 
+-}
 
+
 ------------------------------------------------------------------------
 -- Extra lazy properties
 
@@ -1586,16 +2267,22 @@
     ,("dropWhile",          mytest prop_dropWhile)
     ,("break",              mytest prop_break)
     ,("span",               mytest prop_span)
+    ,("splitAt",               mytest prop_splitAt)
     ,("break/span",         mytest prop_breakspan)
 --     ,("break/breakByte",    mytest prop_breakByte)
 --     ,("span/spanByte",      mytest prop_spanByte)
     ,("split",              mytest prop_split)
     ,("splitWith",          mytest prop_splitWith)
+    ,("splitWith",          mytest prop_splitWith_D)
+    ,("splitWith",          mytest prop_splitWith_C)
     ,("join.split/id",      mytest prop_joinsplit)
 --  ,("join/joinByte",      mytest prop_joinjoinByte)
     ,("group",              mytest prop_group)
     ,("groupBy",            mytest prop_groupBy)
+    ,("groupBy",            mytest prop_groupBy_LC)
     ,("index",              mytest prop_index)
+    ,("index",              mytest prop_index_D)
+    ,("index",              mytest prop_index_C)
     ,("elemIndex",          mytest prop_elemIndex)
     ,("elemIndices",        mytest prop_elemIndices)
     ,("count/elemIndices",  mytest prop_count)
@@ -1612,4 +2299,5 @@
 --  ,("filterNotByte 2",    mytest prop_filterNotByte2)
     ,("isPrefixOf",         mytest prop_isPrefixOf)
     ,("concatMap",          mytest prop_concatMap)
+    ,("isSpace",            mytest prop_isSpaceWord8)
     ]
diff --git a/tests/QuickCheckUtils.hs b/tests/QuickCheckUtils.hs
--- a/tests/QuickCheckUtils.hs
+++ b/tests/QuickCheckUtils.hs
@@ -9,6 +9,7 @@
 import Text.Show.Functions
 
 import Control.Monad        ( liftM2 )
+import Control.Monad.Instances
 import Data.Char
 import Data.List
 import Data.Word
@@ -19,24 +20,53 @@
 import Data.ByteString.Fusion
 import qualified Data.ByteString      as P
 import qualified Data.ByteString.Lazy as L
-import qualified Data.ByteString.Lazy.Internal as L (ByteString(..))
+import qualified Data.ByteString.Lazy.Internal as L (checkInvariant,ByteString(..))
 
 import qualified Data.ByteString.Char8      as PC
 import qualified Data.ByteString.Lazy.Char8 as LC
 
+{-
+
+-- HUGS needs: 
+
+instance Functor ((->) r) where
+        fmap = (.)
+
+instance (Arbitrary a) => Arbitrary (Maybe a) where
+  arbitrary            = sized arbMaybe
+   where
+    arbMaybe 0 = return Nothing
+    arbMaybe n = fmap Just (resize (n-1) arbitrary)
+  coarbitrary Nothing  = variant 0
+  coarbitrary (Just x) = variant 1 . coarbitrary x
+
+instance Monad ((->) r) where
+        return = const
+        f >>= k = \ r -> k (f r) r
+
+instance Functor ((,) a) where
+        fmap f (x,y) = (x, f y)
+
+instance Functor (Either a) where
+        fmap _ (Left x) = Left x
+        fmap f (Right y) = Right (f y)
+
+-}
+
 -- Enable this to get verbose test output. Including the actual tests.
 debug = False
 
-mytest :: Testable a => a -> Int -> IO ()
+mytest :: Testable a => a -> Int -> IO (Bool, Int)
 mytest a n = mycheck defaultConfig
     { configMaxTest=n
     , configEvery= \n args -> if debug then show n ++ ":\n" ++ unlines args else [] } a
 
-mycheck :: Testable a => Config -> a -> IO ()
+mycheck :: Testable a => Config -> a -> IO (Bool, Int)
 mycheck config a =
   do rnd <- newStdGen
      mytests config (evaluate a) rnd 0 0 []
 
+{-
 mytests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO ()
 mytests config gen rnd0 ntest nfail stamps
   | ntest == configMaxTest config = do done "OK," ntest stamps
@@ -57,7 +87,29 @@
      where
       result      = generate (configSize config ntest) rnd2 gen
       (rnd1,rnd2) = split rnd0
+-}
 
+mytests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO (Bool, Int)
+mytests config gen rnd0 ntest nfail stamps
+    | ntest == configMaxTest config = done "OK," ntest stamps >> return (True, ntest)
+    | nfail == configMaxFail config = done "Arguments exhausted after" ntest stamps >> return (True, ntest)
+    | otherwise               =
+      do putStr (configEvery config ntest (arguments result)) >> hFlush stdout
+         case ok result of
+           Nothing    ->
+             mytests config gen rnd1 ntest (nfail+1) stamps
+           Just True  ->
+             mytests config gen rnd1 (ntest+1) nfail (stamp result:stamps)
+           Just False ->
+             putStr ( "Falsifiable after "
+                   ++ show ntest
+                   ++ " tests:\n"
+                   ++ unlines (arguments result)
+                    ) >> hFlush stdout >> return (False, ntest)
+     where
+      result      = generate (configSize config ntest) rnd2 gen
+      (rnd1,rnd2) = split rnd0
+
 done :: String -> Int -> [[String]] -> IO ()
 done mesg ntest stamps =
   do putStr ( mesg ++ " " ++ show ntest ++ " tests" ++ table )
@@ -89,9 +141,11 @@
     arbitrary     = choose ('\0','\255')
     coarbitrary c = variant (ord c `rem` 4)
 
+{-
 instance (Arbitrary a, Arbitrary b) => Arbitrary (PairS a b) where
   arbitrary             = liftM2 (:*:) arbitrary arbitrary
   coarbitrary (a :*: b) = coarbitrary a . coarbitrary b
+-}
 
 instance Arbitrary Word8 where
     arbitrary = choose (97, 105)
@@ -101,10 +155,12 @@
   arbitrary     = sized $ \n -> choose (-fromIntegral n,fromIntegral n)
   coarbitrary n = variant (fromIntegral (if n >= 0 then 2*n else 2*(-n) + 1))
 
+{-
 instance Arbitrary a => Arbitrary (MaybeS a) where
   arbitrary            = do a <- arbitrary ; elements [NothingS, JustS a]
   coarbitrary NothingS = variant 0
   coarbitrary _        = variant 1 -- ok?
+-}
 
 {-
 instance Arbitrary Char where
@@ -130,7 +186,7 @@
                             (x,g) -> (fromIntegral x, g)
 
 instance Arbitrary L.ByteString where
-    arbitrary     = arbitrary >>= return . L.fromChunks . filter (not. P.null) -- maintain the invariant.
+    arbitrary     = arbitrary >>= return . L.checkInvariant . L.fromChunks . filter (not. P.null)  -- maintain the invariant.
     coarbitrary s = coarbitrary (L.unpack s)
 
 instance Arbitrary P.ByteString where
@@ -168,14 +224,18 @@
 instance Model P [Char] where model = PC.unpack
 instance Model B [W]    where model = L.unpack  . checkInvariant
 instance Model B [Char] where model = LC.unpack . checkInvariant
+instance Model Char Word8 where model = fromIntegral . ord
 
 -- Types are trivially modeled by themselves
 instance Model Bool  Bool         where model = id
 instance Model Int   Int          where model = id
+instance Model P     P            where model = id
+instance Model B     B            where model = id
 instance Model Int64 Int64        where model = id
 instance Model Int64 Int          where model = fromIntegral
 instance Model Word8 Word8        where model = id
 instance Model Ordering Ordering  where model = id
+instance Model Char Char  where model = id
 
 -- More structured types are modeled recursively, using the NatTrans class from Gofer.
 class (Functor f, Functor g) => NatTrans f g where
@@ -185,6 +245,8 @@
 instance NatTrans [] []             where eta = id
 instance NatTrans Maybe Maybe       where eta = id
 instance NatTrans ((->) X) ((->) X) where eta = id
+instance NatTrans ((->) Char) ((->) Char) where eta = id
+
 instance NatTrans ((->) W) ((->) W) where eta = id
 
 -- We have a transformation of pairs, if the pairs are in Model
@@ -197,11 +259,7 @@
 
 -- In a form more useful for QC testing (and it's lazy)
 checkInvariant :: L.ByteString -> L.ByteString
-checkInvariant cs0 = check cs0
-  where check L.Empty        = L.Empty
-        check (L.Chunk c cs)
-	       | P.null c    = error ("invariant violation: " ++ show cs0)
-               | otherwise   = L.Chunk c (check cs)
+checkInvariant = L.checkInvariant
 
 abstr :: L.ByteString -> P.ByteString
 abstr = P.concat . L.toChunks 
diff --git a/tests/Rules.hs b/tests/Rules.hs
new file mode 100644
--- /dev/null
+++ b/tests/Rules.hs
@@ -0,0 +1,32 @@
+module Rules where
+--
+-- Tests to ensure rules are firing.
+--
+
+import qualified Data.ByteString.Char8       as C
+import qualified Data.ByteString             as P
+import qualified Data.ByteString.Lazy        as L
+import qualified Data.ByteString.Lazy.Char8  as D
+import Data.List
+import Data.Char
+import QuickCheckUtils
+
+
+prop_break_C x = C.break ((==) x) `eq1` break ((==) x)
+prop_break_P x = P.break ((==) x) `eq1` break ((==) x)
+prop_intercalate_P c = (\s1 s2 -> P.intercalate (P.singleton c) (s1 : s2 : []))
+                        `eq2`
+                       (\s1 s2 -> intercalate [c] (s1 : s2 : []))
+
+prop_break_isSpace_C = C.break isSpace `eq1` break isSpace
+prop_dropWhile_isSpace_C = C.dropWhile isSpace `eq1` dropWhile isSpace
+
+rules =
+    [("break (==)" ,         mytest prop_break_C)
+    ,("break (==)" ,         mytest prop_break_P)
+    ,("break isSpace" ,      mytest prop_break_isSpace_C)
+
+    ,("dropWhile isSpace" ,  mytest prop_dropWhile_isSpace_C)
+
+    ,("intercalate      " ,  mytest prop_intercalate_P)
+    ]
diff --git a/tests/Words.hs b/tests/Words.hs
new file mode 100644
--- /dev/null
+++ b/tests/Words.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE BangPatterns #-}
+
+import System.Environment
+import Control.Applicative
+import Data.List
+import Data.Ord
+import qualified Data.Map as M
+import qualified Data.ByteString.Char8 as S
+
+import Data.ByteString.Internal
+import Data.ByteString.Unsafe
+import Foreign
+
+main = do
+    f <- head <$> getArgs
+    x <- S.readFile f
+    let t = foldl' count M.empty (S.words x) :: M.Map S.ByteString Int
+    print . take 20 . sortBy (flip (comparing snd)) . M.toList $ t
+
+count counts word = M.insertWith' (+) (word) 1 counts
+
+
+
+
+
+
+
+------------------------------------------------------------------------
+-- a different Ord
+
+newtype OrdString = OrdString S.ByteString
+    deriving (Eq, Show)
+
+instance Ord OrdString where
+    compare (OrdString p) (OrdString q) = compareBytes p q
+
+compareBytes :: ByteString -> ByteString -> Ordering
+compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2)
+    | len1 == 0  && len2 == 0                     = EQ  -- short cut for empty strings
+    | fp1 == fp2 && off1 == off2 && len1 == len2  = EQ  -- short cut for the same string
+--  | max len1 len2 > 1                           = inlinePerformIO $
+    | otherwise                                   = inlinePerformIO $
+    withForeignPtr fp1 $ \p1 ->
+    withForeignPtr fp2 $ \p2 -> do
+        i <- memcmp (p1 `plusPtr` off1) (p2 `plusPtr` off2) (fromIntegral $ min len1 len2)
+        return $! case i `compare` 0 of
+                    EQ  -> len1 `compare` len2
+                    x   -> x
+
+
+{-
+    | otherwise                                   = inlinePerformIO $
+    withForeignPtr fp1 $ \p1 ->
+        withForeignPtr fp2 $ \p2 ->
+            cmp (p1 `plusPtr` off1)
+                (p2 `plusPtr` off2) 0 len1 len2
+-}
+
+-- XXX todo.
+cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering
+cmp p1 p2 n len1 len2
+      | n == len1 = if n == len2 then return EQ else return LT
+      | n == len2 = return GT
+      | otherwise = do
+          a <- peekByteOff p1 n :: IO Word8
+          b <- peekByteOff p2 n
+          case a `compare` b of
+                EQ -> cmp p1 p2 (n+1) len1 len2
+                LT -> return LT
+                GT -> return GT
diff --git a/tests/pack.hs b/tests/pack.hs
new file mode 100644
--- /dev/null
+++ b/tests/pack.hs
@@ -0,0 +1,3 @@
+import Data.ByteString.Char8
+
+main = print ("abcdef" :: ByteString)
diff --git a/tests/revcomp.hs b/tests/revcomp.hs
--- a/tests/revcomp.hs
+++ b/tests/revcomp.hs
@@ -6,7 +6,9 @@
 --
 import GHC.Base
 import Data.Char
-import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B
+import qualified Data.ByteString.Unsafe   as B
+import qualified Data.ByteString.Internal as B
 
 main = B.getContents >>= process B.empty []
 
@@ -16,8 +18,8 @@
     | x == '>'  = write h b >> process h' [] ps'
     | x == '\n' = process h b xs
     | otherwise = process h ((complement . toUpper $ x) : b) xs
-    where (x,xs)   = (B.unsafeHead ps, B.unsafeTail ps)
-          (h',ps') = B.breakOn '\n' ps
+    where (x,xs)   = (B.w2c (B.unsafeHead ps), B.unsafeTail ps)
+          (h',ps') = B.break (=='\n') ps
 
 write h s
     | B.null h  = return ()
diff --git a/tests/test-compare.hs b/tests/test-compare.hs
new file mode 100644
--- /dev/null
+++ b/tests/test-compare.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE BangPatterns #-}
+
+import qualified Data.ByteString.Char8 as S
+import Data.ByteString.Internal
+import Data.ByteString.Unsafe
+import Foreign
+import Control.Monad
+import System.Environment
+import System.CPUTime
+import Text.Printf
+import Foreign.ForeignPtr
+
+time :: Show t => IO t -> IO t
+time a = do
+    start <- getCPUTime
+    v <- a
+    v `seq` return ()
+    end   <- getCPUTime
+    print v
+    let diff = (fromIntegral (end - start)) / (10^12)
+    printf "Computation time: %0.3f sec\n" (diff :: Double)
+    return v
+
+main = do
+    [f,g,n,m] <- getArgs
+    x <- S.readFile f
+    y <- S.readFile g
+    forM_ [read n .. read m] $ \i -> do
+        print i
+        time (-- replicateM_ 100000000 $
+                    return $ S.take i x `compareBytes`  S.take i y
+                            )
+        time (-- replicateM_ 100000000 $
+                    return $ S.take i x `compareBytesC` S.take i y
+                            )
+
+------------------------------------------------------------------------
+
+compareBytes :: ByteString -> ByteString -> Ordering
+compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2)
+--    | len1 == 0  && len2 == 0                     = EQ  -- short cut for empty strings
+--    | fp1 == fp2 && off1 == off2 && len1 == len2  = EQ  -- short cut for the same string
+    | otherwise                                   = inlinePerformIO $
+    withForeignPtr fp1 $ \p1 ->
+        withForeignPtr fp2 $ \p2 ->
+            cmp (p1 `plusPtr` off1)
+                (p2 `plusPtr` off2) 0 len1 len2
+ 
+cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering
+cmp p1 p2 n len1 len2
+      | n == len1 = if n == len2 then return EQ else return LT
+      | n == len2 = return GT
+      | otherwise = do
+          a <- peekByteOff p1 n :: IO Word8
+          b <- peekByteOff p2 n
+          case a `compare` b of
+                EQ -> cmp p1 p2 (n+1) len1 len2
+                LT -> return LT
+                GT -> return GT
+ 
+compareBytesC (PS x1 s1 l1) (PS x2 s2 l2)
+    | l1 == 0  && l2 == 0               = EQ  -- short cut for empty strings
+    | x1 == x2 && s1 == s2 && l1 == l2  = EQ  -- short cut for the same string
+    | otherwise                         = inlinePerformIO $
+        withForeignPtr x1 $ \p1 ->
+        withForeignPtr x2 $ \p2 -> do
+            i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2) (fromIntegral $ min l1 l2)
+            return $! case i `compare` 0 of
+                        EQ  -> l1 `compare` l2
+                        x   -> x
+{-# INLINE compareBytes #-}
+
