diff --git a/CONTRIBUTORS b/CONTRIBUTORS
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -7,3 +7,4 @@
 
 In addition to the above, many thanks for comments and advice provided by:
 Johan Tibell
+Echo Nolan
diff --git a/Examples/wave_reader.hs b/Examples/wave_reader.hs
--- a/Examples/wave_reader.hs
+++ b/Examples/wave_reader.hs
@@ -3,7 +3,7 @@
 {-# LANGUAGE BangPatterns #-}
 module Main where
 
-import Data.Iteratee
+import Data.Iteratee as Iter
 import Data.Iteratee.Codecs.Wave
 import qualified Data.IntMap as IM
 import Data.List (foldl')
@@ -38,12 +38,7 @@
 
 -- an iteratee that calculates the maximum value found so far.
 -- this could be written with head as well, however it is more
--- efficient to operate on an entire chunk at once.
+-- efficient to use foldl'
 maxIter :: IterateeG [] Double IO Double
-maxIter = m 0
-  where
-  m n = IterateeG (step n)
-  step acc (Chunk []) = return $ Cont (m acc) Nothing
-  step acc (Chunk xs) = return $ Cont (m $! foldl' (max . abs) acc xs) Nothing
-  step acc str = return $ Done acc str
+maxIter = Iter.foldl' (flip (max . abs)) 0
 
diff --git a/iteratee.cabal b/iteratee.cabal
--- a/iteratee.cabal
+++ b/iteratee.cabal
@@ -1,5 +1,5 @@
 Name:		iteratee
-Version:        0.2.3
+Version:        0.2.4
 Cabal-Version:  >= 1.2
 Description:	The IterateeGM monad provides strict, safe, and functional
                 I/O.  In addition to pure Iteratee processors, file IO and 
@@ -26,13 +26,11 @@
 
 Library
  Hs-Source-Dirs:        src
- ghc-options:           -Wall -fexcess-precision -fno-method-sharing
+ ghc-options:           -Wall
  if flag(splitBase)
    build-depends:       base >= 3, base < 5
  else
    build-depends:       base < 3
- if impl(ghc >= 6.10)
-   ghc-options:         -fsimplifier-phases=4
  if os(windows)
    cpp-options:         -DUSE_WINDOWS
    other-modules:       Data.Iteratee.IO.Windows
diff --git a/src/Data/Iteratee/Base.hs b/src/Data/Iteratee/Base.hs
--- a/src/Data/Iteratee/Base.hs
+++ b/src/Data/Iteratee/Base.hs
@@ -194,9 +194,9 @@
 joinI :: (SC.StreamChunk s el, SC.StreamChunk s' el', Monad m) =>
          IterateeG s el m (IterateeG s' el' m a) ->
          IterateeG s el m a
-joinI m = IterateeG (\str -> runIter m str >>= docase)
+joinI m = IterateeG (docase <=< runIter m)
   where
-  docase (Done ma str) = run ma >>= \a -> return (Done a str)
+  docase (Done ma str) = liftM (flip Done str) (run ma)
   docase (Cont k mErr) = return $ Cont (joinI k) mErr
 
 -- It turns out, IterateeG form a monad. We can use the familiar do
@@ -210,7 +210,7 @@
              IterateeG s el m a ->
              (a -> IterateeG s el m b) ->
              IterateeG s el m b
-iterBind m f = IterateeG $ \str -> (runIter m str >>= docase)
+iterBind m f = IterateeG (docase <=< runIter m)
   where
   docase (Done a str)  = runIter (f a) str
   docase (Cont k mErr) = return $ Cont (k `iterBind` f) mErr
@@ -219,7 +219,7 @@
 
 instance (Monad m, Functor m) =>
   Functor (IterateeG s el m) where
-  fmap f m = IterateeG $ \str -> runIter m str >>= docase
+  fmap f m = IterateeG (docase <=< runIter m)
     where
     -- docase :: IterGV s el m a -> m (IterGV s el m a)
     docase (Done a stream) = return $ Done (f a) stream
@@ -227,10 +227,10 @@
 
 instance (Monad m, Functor m) => Applicative (IterateeG s el m) where
   pure    = return
-  m <*> a = m >>= \f -> fmap f a
+  m <*> a = m >>= flip fmap a
 
 instance MonadTrans (IterateeG s el) where
-  lift m = IterateeG $ \str -> m >>= \a -> return $ Done a str
+  lift m = IterateeG $ \str -> liftM (flip Done str) m
 
 instance (MonadIO m) => MonadIO (IterateeG s el m) where
   liftIO = lift . liftIO
@@ -269,7 +269,7 @@
 checkErr :: (Monad m, SC.StreamChunk s el) =>
               IterateeG s el m a ->
               IterateeG s el m (Either ErrMsg a)
-checkErr iter = IterateeG (\str -> runIter iter str >>= check)
+checkErr iter = IterateeG (check <=< runIter iter)
   where
   check (Done a str) = return $ Done (Right a) str
   check (Cont _ (Just err)) = return $ Done (Left err) mempty
@@ -425,8 +425,7 @@
   check n (Done x _)        = drop n >> (return $ return x)
   check n (Cont x Nothing)  = take n x
   check n (Cont _ (Just e)) = drop n >> throwErr e
-  done s1 s2 = runIter iter s1 >>= checkIfDone return >>= \i' ->
-               return (Done i' s2)
+  done s1 s2 = liftM (flip Done s2) (runIter iter s1 >>= checkIfDone return)
 
 
 -- |Read n elements from a stream and apply the given iteratee to the
@@ -450,8 +449,7 @@
   step _n str            = done str str
   check _n' (Done a str)   = return $ Done (return a) str
   check n'  (Cont k mErr)  = return $ Cont (takeR n' k) mErr
-  done s1 s2 = runIter iter s1 >>= checkIfDone return >>= \i' ->
-               return (Done i' s2)
+  done s1 s2 = liftM (flip Done s2) (runIter iter s1 >>= checkIfDone return)
 
 
 -- |Map the stream: yet another iteratee transformer
@@ -463,8 +461,7 @@
 mapStream :: (SC.StreamChunk s el, SC.StreamChunk s el', Monad m) =>
               (el -> el') ->
               EnumeratorN s el s el' m a
-mapStream f iter = IterateeG (\str -> runIter iter (strMap (SC.cMap f) str) >>=
-                   check)
+mapStream f iter = IterateeG ((check <=< runIter iter) . strMap (SC.cMap f))
   where
   check (Done a _) = return $ Done (return a) (Chunk LL.empty)
   check (Cont k mErr) = return $ Cont (mapStream f k) mErr
@@ -489,8 +486,7 @@
   docase (Cont k Nothing)  = convStream fi k
   docase (Cont _ (Just e)) = return $ throwErr e
 
-{-# SPECIALIZE convStream :: IterateeG s el IO (Maybe (s' el')) -> EnumeratorN s el s' el' IO a #-}
-
+{-# INLINE convStream #-}
 
 -- |Creates an enumerator with only elements from the stream that
 -- satisfy the predicate function.
@@ -512,9 +508,10 @@
          (a -> el -> a) ->
          a ->
          IterateeG s el m a
-foldl f i = IterateeG step
+foldl f i = iter
   where
-  step (Chunk xs) | LL.null xs = return $ Cont (foldl f i) Nothing
+  iter = IterateeG step
+  step (Chunk xs) | LL.null xs = return $ Cont (iter) Nothing
   step (Chunk xs) = return $ Cont (foldl f (FLL.foldl f i xs)) Nothing
   step stream     = return $ Done i stream
 
@@ -523,9 +520,10 @@
           (a -> el -> a) ->
           a ->
           IterateeG s el m a
-foldl' f i = IterateeG step
+foldl' f i = iter
   where
-  step (Chunk xs) | LL.null xs = return $ Cont (foldl' f i) Nothing
+  iter = IterateeG step
+  step (Chunk xs) | LL.null xs = return $ Cont (iter) Nothing
   step (Chunk xs) = return $ Cont (foldl' f $! FLL.foldl' f i xs) Nothing
   step stream     = return $ Done i stream
 
@@ -537,6 +535,8 @@
 foldl1 f = IterateeG step
   where
   step (Chunk xs) | LL.null xs = return $ Cont (foldl1 f) Nothing
+  -- After the first chunk, just use regular foldl in order to account for
+  -- the accumulator.
   step (Chunk xs) = return $ Cont (foldl f (FLL.foldl1 f xs)) Nothing
   step stream     = return $ Cont (foldl1 f) (Just (setEOF stream))
 
@@ -585,7 +585,7 @@
 
 (>.):: (SC.StreamChunk s el, Monad m) =>
        EnumeratorGM s el m a -> EnumeratorGM s el m a -> EnumeratorGM s el m a
-(>.) e1 e2 i1 = e1 i1 >>= e2
+(>.) e1 e2 = e2 <=< e1
 
 -- |The pure 1-chunk enumerator
 -- It passes a given list of elements to the iteratee in one chunk
diff --git a/src/Data/Iteratee/Base/StreamChunk.hs b/src/Data/Iteratee/Base/StreamChunk.hs
--- a/src/Data/Iteratee/Base/StreamChunk.hs
+++ b/src/Data/Iteratee/Base/StreamChunk.hs
@@ -77,7 +77,9 @@
 
 -- |Class of streams which can be filled from a 'Ptr'.  Typically these
 -- are streams which can be read from a file.
-class StreamChunk s el => ReadableChunk s el where
+-- The Int parameter is the length of the data in bytes.
+-- N.B. The pointer must not be returned or used after readFromPtr completes.
+class (StreamChunk s el, Storable el) => ReadableChunk s el where
   readFromPtr :: Ptr (el) -> Int -> IO (s el)
 
 instance (Storable el) => ReadableChunk [] el where
diff --git a/src/Data/Iteratee/IO/Fd.hs b/src/Data/Iteratee/IO/Fd.hs
--- a/src/Data/Iteratee/IO/Fd.hs
+++ b/src/Data/Iteratee/IO/Fd.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE CPP, ScopedTypeVariables #-}
 
 -- |Random and Binary IO with generic Iteratees, using File Descriptors for IO.
 -- when available, these are the preferred functions for performing IO as they
@@ -26,6 +26,7 @@
 
 import Foreign.Ptr
 import Foreign.Marshal.Alloc
+import Foreign.Storable
 
 import System.IO (SeekMode(..))
 
@@ -37,10 +38,10 @@
 -- |The enumerator of a POSIX File Descriptor.  This version enumerates
 -- over the entire contents of a file, in order, unless stopped by
 -- the iteratee.  In particular, seeking is not supported.
-enumFd :: ReadableChunk s el => Fd -> EnumeratorGM s el IO a
+enumFd :: forall a s el.(ReadableChunk s el) => Fd -> EnumeratorGM s el IO a
 enumFd fd iter' = allocaBytes (fromIntegral buffer_size) $ loop iter'
   where
-    buffer_size = 4096
+    buffer_size = fromIntegral $ 2048 - (mod 2048 $ sizeOf (undefined :: el))
     loop iter p = do
       n <- myfdRead fd (castPtr p) buffer_size
       case n of
@@ -56,13 +57,13 @@
 
 -- |The enumerator of a POSIX File Descriptor: a variation of enumFd that
 -- supports RandomIO (seek requests)
-enumFdRandom :: ReadableChunk s el => Fd -> EnumeratorGM s el IO a
+enumFdRandom :: forall a s el.(ReadableChunk s el) => Fd -> EnumeratorGM s el IO a
 enumFdRandom fd iter =
  allocaBytes (fromIntegral buffer_size) (loop (0,0) iter)
  where
   -- this can be usefully varied.  Values between 512 and 4096 seem
   -- to provide the best performance for most cases.
-  buffer_size = 4096
+  buffer_size = fromIntegral $ 4096 - (mod 4096 $ sizeOf (undefined :: el))
   -- the first argument of loop is (off,len), describing which part
   -- of the file is currently in the buffer 'p'
 {-
diff --git a/src/Data/Iteratee/IO/Handle.hs b/src/Data/Iteratee/IO/Handle.hs
--- a/src/Data/Iteratee/IO/Handle.hs
+++ b/src/Data/Iteratee/IO/Handle.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
 -- |Random and Binary IO with generic Iteratees.  These functions use Handles
 -- for IO operations, and are provided for compatibility.  When available,
 -- the File Descriptor based functions are preferred as these wastefully
@@ -23,6 +25,7 @@
 
 import Foreign.Ptr
 import Foreign.Marshal.Alloc
+import Foreign.Storable
 
 import System.IO
 
@@ -33,10 +36,10 @@
 -- |The enumerator of a file Handle.  This version enumerates
 -- over the entire contents of a file, in order, unless stopped by
 -- the iteratee.  In particular, seeking is not supported.
-enumHandle :: ReadableChunk s el => Handle -> EnumeratorGM s el IO a
+enumHandle :: forall a s el.(ReadableChunk s el) => Handle -> EnumeratorGM s el IO a
 enumHandle h i = allocaBytes (fromIntegral buffer_size) $ loop i
   where
-    buffer_size = 4096
+    buffer_size = 4096 - (mod 4096 $ sizeOf (undefined :: el))
     loop iter p = do
       n <- (try $ hGetBuf h p buffer_size) :: IO (Either SomeException Int)
       case n of
@@ -53,13 +56,13 @@
 
 -- |The enumerator of a Handle: a variation of enumHandle that
 -- supports RandomIO (seek requests)
-enumHandleRandom :: ReadableChunk s el => Handle -> EnumeratorGM s el IO a
+enumHandleRandom :: forall a s el.(ReadableChunk s el) => Handle -> EnumeratorGM s el IO a
 enumHandleRandom h iter =
  allocaBytes (fromIntegral buffer_size) (loop (0,0) iter)
  where
   -- this can be usefully varied.  Values between 512 and 4096 seem
   -- to provide the best performance for most cases.
-  buffer_size = 4096
+  buffer_size = 4096 - (mod 4096 $ sizeOf (undefined :: el))
   -- the first argument of loop is (off,len), describing which part
   -- of the file is currently in the buffer 'p'
 {-
diff --git a/src/Data/Iteratee/WrappedByteString.hs b/src/Data/Iteratee/WrappedByteString.hs
--- a/src/Data/Iteratee/WrappedByteString.hs
+++ b/src/Data/Iteratee/WrappedByteString.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, BangPatterns #-}
 
 module Data.Iteratee.WrappedByteString (
   WrappedByteString (..)
@@ -14,7 +13,9 @@
 import qualified Data.ListLike as LL
 import Data.Word
 import Data.Monoid
-import Foreign.ForeignPtr
+import Foreign.Ptr
+import Foreign.Marshal.Array
+import Control.Monad
 
 -- |Wrap a Data.ByteString ByteString
 newtype WrappedByteString a = WrapBS { unWrap :: BBase.ByteString }
@@ -27,15 +28,15 @@
   foldl f z = BW.foldl f z . unWrap
   foldr f z = BW.foldr f z . unWrap
 
+-- Thanks to Echo Nolan for indicating that the bytestring must copy
+-- data to a new ptr to preserve referential transparency.
 instance SC.ReadableChunk WrappedByteString Word8 where
-  readFromPtr p l = do
-    fptr <- newForeignPtr_ p
-    return . WrapBS $ BBase.fromForeignPtr fptr 0 l
+  readFromPtr buf l = liftM WrapBS $! BBase.create l $ \newp ->
+                    copyArray newp buf l -- must copy from the buffer
 
 instance SC.ReadableChunk WrappedByteString Char where
-  readFromPtr p l = do
-    fptr <- newForeignPtr_ p
-    return . WrapBS $ BBase.fromForeignPtr (castForeignPtr fptr) 0 l
+  readFromPtr buf l = liftM WrapBS $! BBase.create l $ \newp ->
+                    copyArray newp (castPtr buf) l --must copy data from buffer
 
 instance LL.ListLike (WrappedByteString Word8) Word8 where
   length        = BW.length . unWrap
diff --git a/tests/testIteratee.hs b/tests/testIteratee.hs
--- a/tests/testIteratee.hs
+++ b/tests/testIteratee.hs
@@ -1,6 +1,8 @@
 {-# OPTIONS_GHC -O #-}
 {-# LANGUAGE NoMonomorphismRestriction #-}
 
+import Prelude as P
+
 import QCUtils
 
 import Test.Framework (defaultMain, testGroup)
@@ -94,13 +96,13 @@
 prop_break2 f xs = runner1 (enumPure1Chunk xs (Iter.break f >> stream2list)) == snd (break f xs)
   where types = xs :: [Int]
 
-prop_head xs = length xs > 0 ==> runner1 (enumPure1Chunk xs Iter.head) == head xs
+prop_head xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs Iter.head) == head xs
   where types = xs :: [Int]
 
-prop_head2 xs = length xs > 0 ==> runner1 (enumPure1Chunk xs (Iter.head >> stream2list)) == tail xs
+prop_head2 xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs (Iter.head >> stream2list)) == tail xs
   where types = xs :: [Int]
 
-prop_heads xs = runner1 (enumPure1Chunk xs $ heads xs) == length xs
+prop_heads xs = runner1 (enumPure1Chunk xs $ heads xs) == P.length xs
   where types = xs :: [Int]
 
 prop_heads2 xs = runner1 (enumPure1Chunk xs $ heads [] >>= \c ->
@@ -154,7 +156,7 @@
                  == runner1 (enumPure1Chunk xs i)
   where types = (xs :: [Int], i :: I)
 
-prop_nullH xs = length xs > 0 ==>
+prop_nullH xs = P.length xs > 0 ==>
                 runner1 (enumPure1Chunk xs =<< enumPure1Chunk [] Iter.head)
                 == runner1 (enumPure1Chunk xs Iter.head)
   where types = (xs :: [Int])
@@ -190,29 +192,29 @@
 prop_convId xs = runner1 (enumPure1Chunk xs convId) == Just xs
   where types = xs :: [Int]
 
-prop_convstream xs i = length xs > 0 ==>
+prop_convstream xs i = P.length xs > 0 ==>
                        runner2 (enumPure1Chunk xs $ convStream convId i)
                        == runner1 (enumPure1Chunk xs i)
   where types = (xs :: [Int], i :: I)
 
-prop_convstream2 xs = length xs > 0 ==>
+prop_convstream2 xs = P.length xs > 0 ==>
                       runner2 (enumPure1Chunk xs $ convStream convId Iter.head)
                       == runner1 (enumPure1Chunk xs Iter.head)
   where types = (xs :: [Int])
 
-prop_convstream3 xs = length xs > 0 ==>
+prop_convstream3 xs = P.length xs > 0 ==>
                       runner2 (enumPure1Chunk xs $ convStream convId stream2list)
                       == runner1 (enumPure1Chunk xs stream2list)
   where types = (xs :: [Int])
 
 prop_take xs n = n >= 0 ==>
                  runner2 (enumPure1Chunk xs $ Iter.take n stream2list)
-                 == runner1 (enumPure1Chunk (Prelude.take n xs) stream2list)
+                 == runner1 (enumPure1Chunk (P.take n xs) stream2list)
   where types = (xs :: [Int])
 
 prop_take2 xs n = n > 0 ==>
                   runner2 (enumPure1Chunk xs $ Iter.take n peek)
-                  == runner1 (enumPure1Chunk (Prelude.take n xs) peek)
+                  == runner1 (enumPure1Chunk (P.take n xs) peek)
   where types = (xs :: [Int])
 
 prop_takeR xs n = n >= 0 ==>
@@ -226,7 +228,7 @@
 {-
 -- this isn't true, since lines "\r" returns ["\r"], and IC.line should
 -- return Right "".  Not sure what a real test would be...
-prop_line xs = length xs > 0 ==>
+prop_line xs = P.length xs > 0 ==>
                fromEither (runner1 (enumPure1Chunk xs $ IC.line))
                == head (lines xs)
   where
