diff --git a/bench/Blocks.hs b/bench/Blocks.hs
deleted file mode 100644
--- a/bench/Blocks.hs
+++ /dev/null
@@ -1,62 +0,0 @@
-{-# LANGUAGE Rank2Types #-}
-
-module Blocks where
-
-import Control.Monad
-import Control.Monad.ST
-
-import Data.Vector.Unboxed.Mutable
-
-import System.CPUTime
-
-import System.Random.MWC (GenIO, Variate(..))
-
--- Some conveniences for doing evil stuff in the ST monad.
--- All the tests get run in IO, but uvector stuff happens
--- in ST, so we temporarily coerce.
-clock :: IO Integer
-clock = getCPUTime
-
--- Strategies for filling the initial arrays
-rand :: Variate e => GenIO -> Int -> IO e
-rand g _ = uniform g
-
-ascend :: Num e => Int -> IO e
-ascend = return . fromIntegral
-
-descend :: Num e => e -> Int -> IO e
-descend m n = return $ m - fromIntegral n
-
-modulo :: Integral e => e -> Int -> IO e
-modulo m n = return $ fromIntegral n `mod` m
-
--- This is the worst case for the median-of-three quicksort
--- used in the introsort implementation.
-medianKiller :: Integral e => e -> Int -> IO e
-medianKiller m n'
-  | n < k     = return $ if even n then n + 1 else n + k
-  | otherwise = return $ (n - k + 1) * 2
- where
- n = fromIntegral n'
- k = m `div` 2
-{-# INLINE medianKiller #-}
-
-initialize :: (Unbox e) => MVector RealWorld e -> Int -> (Int -> IO e) -> IO ()
-initialize arr len fill = init $ len - 1
- where init n = fill n >>= unsafeWrite arr n >> when (n > 0) (init $ n - 1)
-{-# INLINE initialize #-}
-
-speedTest :: (Unbox e) => Int
-                       -> (Int -> IO e)
-                       -> (MVector RealWorld e -> IO ())
-                       -> IO Integer
-speedTest n fill algo = do
-  arr <- new n
-  initialize arr n fill
-  t0 <- clock
-  algo arr
-  t1 <- clock
-  return $ t1 - t0
-{-# INLINE speedTest #-}
-
-
diff --git a/bench/Main.hs b/bench/Main.hs
deleted file mode 100644
--- a/bench/Main.hs
+++ /dev/null
@@ -1,201 +0,0 @@
-{-# LANGUAGE Rank2Types #-}
-
-module Main (main) where
-
-import Prelude hiding (read, length)
-import qualified Prelude as P
-
-import Control.Monad.ST
-import Control.Monad.Error
-
-import Data.Char
-import Data.Ord  (comparing)
-import Data.List (maximumBy)
-
-import Data.Vector.Unboxed.Mutable
-
-import qualified Data.Vector.Algorithms.Insertion    as INS
-import qualified Data.Vector.Algorithms.Intro        as INT
-import qualified Data.Vector.Algorithms.Heap         as H
-import qualified Data.Vector.Algorithms.Merge        as M
-import qualified Data.Vector.Algorithms.Radix        as R
-import qualified Data.Vector.Algorithms.AmericanFlag as AF
-import qualified Data.Vector.Algorithms.Tim          as T
-
-import System.Environment
-import System.Console.GetOpt
-import System.Random.MWC
-
-import Blocks
-
--- Does nothing. For testing the speed/heap allocation of the building blocks.
-noalgo :: (Unbox e) => MVector RealWorld e -> IO ()
-noalgo _ = return ()
-
--- Allocates a temporary buffer, like mergesort for similar purposes as noalgo.
-alloc :: (Unbox e) => MVector RealWorld e -> IO ()
-alloc arr | len <= 4  = arr `seq` return ()
-          | otherwise = (new (len `div` 2) :: IO (MVector RealWorld Int)) >> return ()
- where len = length arr
-
-displayTime :: String -> Integer -> IO ()
-displayTime s elapsed = putStrLn $
-    s ++ " : " ++ show (fromIntegral elapsed / 1e12) ++ " seconds"
-
-run :: String -> IO Integer -> IO ()
-run s t = t >>= displayTime s
-
-sortSuite :: String -> GenIO -> Int -> (MVector RealWorld Int -> IO ()) -> IO ()
-sortSuite str g n sort = do
-  putStrLn $ "Testing: " ++ str
-  run "Random            " $ speedTest n (rand g >=> modulo n) sort
-  run "Sorted            " $ speedTest n ascend sort
-  run "Reverse-sorted    " $ speedTest n (descend n) sort
-  run "Random duplicates " $ speedTest n (rand g >=> modulo 1000) sort
-  let m = 4 * (n `div` 4)
-  run "Median killer     " $ speedTest m (medianKiller m) sort
-
-partialSortSuite :: String -> GenIO -> Int -> Int
-                 -> (MVector RealWorld Int -> Int -> IO ()) -> IO ()
-partialSortSuite str g n k sort = sortSuite str g n (\a -> sort a k)
-
--- -----------------
--- Argument handling
--- -----------------
-
-data Algorithm = DoNothing
-               | Allocate
-               | InsertionSort
-               | IntroSort
-               | IntroPartialSort
-               | IntroSelect
-               | HeapSort
-               | HeapPartialSort
-               | HeapSelect
-               | MergeSort
-               | RadixSort
-               | AmericanFlagSort
-               | TimSort
-               deriving (Show, Read, Enum, Bounded)
-
-data Options = O { algos :: [Algorithm], elems :: Int, portion :: Int, usage :: Bool } deriving (Show)
-
-defaultOptions :: Options
-defaultOptions = O [] 10000 1000 False
-
-type OptionsT = Options -> Either String Options
-
-options :: [OptDescr OptionsT]
-options = [ Option ['A']     ["algorithm"] (ReqArg parseAlgo "ALGO")
-               ("Specify an algorithm to be run. Options:\n" ++ algoOpts)
-          , Option ['n']     ["num-elems"] (ReqArg parseN    "INT")
-               "Specify the size of arrays in algorithms."
-          , Option ['k']     ["portion"]   (ReqArg parseK    "INT")
-               "Specify the number of elements to partial sort/select in\nrelevant algorithms."
-          , Option ['?','v'] ["help"]      (NoArg $ \o -> Right $ o { usage = True })
-               "Show options."
-          ]
- where
- allAlgos :: [Algorithm]
- allAlgos = [minBound .. maxBound]
- algoOpts = fmt allAlgos
- fmt (x:y:zs) = '\t' : pad (show x) ++ show y ++ "\n" ++ fmt zs
- fmt [x]      = '\t' : show x ++ "\n"
- fmt []       = ""
- size         = ("    " ++) . maximumBy (comparing P.length) . map show $ allAlgos
- pad str      = zipWith const (str ++ repeat ' ') size
-
-parseAlgo :: String -> Options -> Either String Options
-parseAlgo "None" o = Right $ o { algos = [] }
-parseAlgo "All"  o = Right $ o { algos = [DoNothing .. AmericanFlagSort] }
-parseAlgo s      o = leftMap (\e -> "Unrecognized algorithm `" ++ e ++ "'")
-                     . fmap (\v -> o { algos = v : algos o }) $ readEither s
-
-leftMap :: (a -> b) -> Either a c -> Either b c
-leftMap f (Left a)  = Left (f a)
-leftMap _ (Right c) = Right c
-
-parseNum :: (Int -> Options) -> String -> Either String Options
-parseNum f = leftMap (\e -> "Invalid numeric argument `" ++ e ++ "'") . fmap f . readEither
-
-parseN, parseK :: String -> Options -> Either String Options
-parseN s o = parseNum (\n -> o { elems   = n }) s
-parseK s o = parseNum (\k -> o { portion = k }) s
-
-readEither :: Read a => String -> Either String a
-readEither s = case reads s of
-  [(x,t)] | all isSpace t -> Right x
-  _                       -> Left s
-
-runTest :: GenIO -> Int -> Int -> Algorithm -> IO ()
-runTest g n k alg = case alg of
-  DoNothing          -> sortSuite        "no algorithm"          g n   noalgo
-  Allocate           -> sortSuite        "allocate"              g n   alloc
-  InsertionSort      -> sortSuite        "insertion sort"        g n   insertionSort
-  IntroSort          -> sortSuite        "introsort"             g n   introSort
-  IntroPartialSort   -> partialSortSuite "partial introsort"     g n k introPSort
-  IntroSelect        -> partialSortSuite "introselect"           g n k introSelect
-  HeapSort           -> sortSuite        "heap sort"             g n   heapSort
-  HeapPartialSort    -> partialSortSuite "partial heap sort"     g n k heapPSort
-  HeapSelect         -> partialSortSuite "heap select"           g n k heapSelect
-  MergeSort          -> sortSuite        "merge sort"            g n   mergeSort
-  RadixSort          -> sortSuite        "radix sort"            g n   radixSort
-  AmericanFlagSort   -> sortSuite        "flag sort"             g n   flagSort
-  TimSort            -> sortSuite        "tim sort"              g n   timSort
-  _                  -> putStrLn $ "Currently unsupported algorithm: " ++ show alg
-
-mergeSort :: MVector RealWorld Int -> IO ()
-mergeSort v = M.sort v
-{-# NOINLINE mergeSort #-}
-
-introSort :: MVector RealWorld Int -> IO ()
-introSort v = INT.sort v
-{-# NOINLINE introSort #-}
-
-introPSort :: MVector RealWorld Int -> Int -> IO ()
-introPSort v k = INT.partialSort v k
-{-# NOINLINE introPSort #-}
-
-introSelect :: MVector RealWorld Int -> Int -> IO ()
-introSelect v k = INT.select v k
-{-# NOINLINE introSelect #-}
-
-heapSort :: MVector RealWorld Int -> IO ()
-heapSort v = H.sort v
-{-# NOINLINE heapSort #-}
-
-heapPSort :: MVector RealWorld Int -> Int -> IO ()
-heapPSort v k = H.partialSort v k
-{-# NOINLINE heapPSort #-}
-
-heapSelect :: MVector RealWorld Int -> Int -> IO ()
-heapSelect v k = H.select v k
-{-# NOINLINE heapSelect #-}
-
-insertionSort :: MVector RealWorld Int -> IO ()
-insertionSort v = INS.sort v
-{-# NOINLINE insertionSort #-}
-
-radixSort :: MVector RealWorld Int -> IO ()
-radixSort v = R.sort v
-{-# NOINLINE radixSort #-}
-
-flagSort :: MVector RealWorld Int -> IO ()
-flagSort v = AF.sort v
-{-# NOINLINE flagSort #-}
-
-timSort :: MVector RealWorld Int -> IO ()
-timSort v = T.sort v
-{-# NOINLINE timSort #-}
-
-main :: IO ()
-main = getArgs >>= \args -> withSystemRandom $ \gen ->
-  case getOpt Permute options args of
-    (fs, _, []) -> case foldl (>>=) (Right defaultOptions) fs of
-      Left err   -> putStrLn $ usageInfo err options
-      Right opts | not (usage opts) ->
-        mapM_ (runTest gen (elems opts) (portion opts)) (algos opts)
-                 | otherwise -> putStrLn $ usageInfo "uvector-algorithms-bench" options
-    (_, _, errs) -> putStrLn $ usageInfo (concat errs) options
-
-
diff --git a/bench/simple/Blocks.hs b/bench/simple/Blocks.hs
new file mode 100644
--- /dev/null
+++ b/bench/simple/Blocks.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE Rank2Types #-}
+
+module Blocks where
+
+import Control.Monad
+import Control.Monad.ST
+
+import Data.Vector.Unboxed.Mutable
+
+import System.CPUTime
+
+import System.Random.MWC (GenIO, Variate(..))
+
+-- Some conveniences for doing evil stuff in the ST monad.
+-- All the tests get run in IO, but uvector stuff happens
+-- in ST, so we temporarily coerce.
+clock :: IO Integer
+clock = getCPUTime
+
+-- Strategies for filling the initial arrays
+rand :: Variate e => GenIO -> Int -> IO e
+rand g _ = uniform g
+
+ascend :: Num e => Int -> IO e
+ascend = return . fromIntegral
+
+descend :: Num e => e -> Int -> IO e
+descend m n = return $ m - fromIntegral n
+
+modulo :: Integral e => e -> Int -> IO e
+modulo m n = return $ fromIntegral n `mod` m
+
+-- This is the worst case for the median-of-three quicksort
+-- used in the introsort implementation.
+medianKiller :: Integral e => e -> Int -> IO e
+medianKiller m n'
+  | n < k     = return $ if even n then n + 1 else n + k
+  | otherwise = return $ (n - k + 1) * 2
+ where
+ n = fromIntegral n'
+ k = m `div` 2
+{-# INLINE medianKiller #-}
+
+initialize :: (Unbox e) => MVector RealWorld e -> Int -> (Int -> IO e) -> IO ()
+initialize arr len fill = initial $ len - 1
+ where initial n = fill n >>= unsafeWrite arr n >> when (n > 0) (initial $ n - 1)
+{-# INLINE initialize #-}
+
+speedTest :: (Unbox e) => Int
+                       -> (Int -> IO e)
+                       -> (MVector RealWorld e -> IO ())
+                       -> IO Integer
+speedTest n fill algo = do
+  arr <- new n
+  initialize arr n fill
+  t0 <- clock
+  algo arr
+  t1 <- clock
+  return $ t1 - t0
+{-# INLINE speedTest #-}
+
+
diff --git a/bench/simple/Main.hs b/bench/simple/Main.hs
new file mode 100644
--- /dev/null
+++ b/bench/simple/Main.hs
@@ -0,0 +1,201 @@
+{-# LANGUAGE Rank2Types #-}
+
+module Main (main) where
+
+import Prelude hiding (read, length)
+import qualified Prelude as P
+
+import Control.Monad.ST
+import Control.Monad.Error
+
+import Data.Char
+import Data.Ord  (comparing)
+import Data.List (maximumBy)
+
+import Data.Vector.Unboxed.Mutable
+
+import qualified Data.Vector.Algorithms.Insertion    as INS
+import qualified Data.Vector.Algorithms.Intro        as INT
+import qualified Data.Vector.Algorithms.Heap         as H
+import qualified Data.Vector.Algorithms.Merge        as M
+import qualified Data.Vector.Algorithms.Radix        as R
+import qualified Data.Vector.Algorithms.AmericanFlag as AF
+import qualified Data.Vector.Algorithms.Tim          as T
+
+import System.Environment
+import System.Console.GetOpt
+import System.Random.MWC
+
+import Blocks
+
+-- Does nothing. For testing the speed/heap allocation of the building blocks.
+noalgo :: (Unbox e) => MVector RealWorld e -> IO ()
+noalgo _ = return ()
+
+-- Allocates a temporary buffer, like mergesort for similar purposes as noalgo.
+alloc :: (Unbox e) => MVector RealWorld e -> IO ()
+alloc arr | len <= 4  = arr `seq` return ()
+          | otherwise = (new (len `div` 2) :: IO (MVector RealWorld Int)) >> return ()
+ where len = length arr
+
+displayTime :: String -> Integer -> IO ()
+displayTime s elapsed = putStrLn $
+    s ++ " : " ++ show (fromIntegral elapsed / 1e12) ++ " seconds"
+
+run :: String -> IO Integer -> IO ()
+run s t = t >>= displayTime s
+
+sortSuite :: String -> GenIO -> Int -> (MVector RealWorld Int -> IO ()) -> IO ()
+sortSuite str g n sort = do
+  putStrLn $ "Testing: " ++ str
+  run "Random            " $ speedTest n (rand g >=> modulo n) sort
+  run "Sorted            " $ speedTest n ascend sort
+  run "Reverse-sorted    " $ speedTest n (descend n) sort
+  run "Random duplicates " $ speedTest n (rand g >=> modulo 1000) sort
+  let m = 4 * (n `div` 4)
+  run "Median killer     " $ speedTest m (medianKiller m) sort
+
+partialSortSuite :: String -> GenIO -> Int -> Int
+                 -> (MVector RealWorld Int -> Int -> IO ()) -> IO ()
+partialSortSuite str g n k sort = sortSuite str g n (\a -> sort a k)
+
+-- -----------------
+-- Argument handling
+-- -----------------
+
+data Algorithm = DoNothing
+               | Allocate
+               | InsertionSort
+               | IntroSort
+               | IntroPartialSort
+               | IntroSelect
+               | HeapSort
+               | HeapPartialSort
+               | HeapSelect
+               | MergeSort
+               | RadixSort
+               | AmericanFlagSort
+               | TimSort
+               deriving (Show, Read, Enum, Bounded)
+
+data Options = O { algos :: [Algorithm], elems :: Int, portion :: Int, usage :: Bool } deriving (Show)
+
+defaultOptions :: Options
+defaultOptions = O [] 10000 1000 False
+
+type OptionsT = Options -> Either String Options
+
+options :: [OptDescr OptionsT]
+options = [ Option ['A']     ["algorithm"] (ReqArg parseAlgo "ALGO")
+               ("Specify an algorithm to be run. Options:\n" ++ algoOpts)
+          , Option ['n']     ["num-elems"] (ReqArg parseN    "INT")
+               "Specify the size of arrays in algorithms."
+          , Option ['k']     ["portion"]   (ReqArg parseK    "INT")
+               "Specify the number of elements to partial sort/select in\nrelevant algorithms."
+          , Option ['?','v'] ["help"]      (NoArg $ \o -> Right $ o { usage = True })
+               "Show options."
+          ]
+ where
+ allAlgos :: [Algorithm]
+ allAlgos = [minBound .. maxBound]
+ algoOpts = fmt allAlgos
+ fmt (x:y:zs) = '\t' : pad (show x) ++ show y ++ "\n" ++ fmt zs
+ fmt [x]      = '\t' : show x ++ "\n"
+ fmt []       = ""
+ size         = ("    " ++) . maximumBy (comparing P.length) . map show $ allAlgos
+ pad str      = zipWith const (str ++ repeat ' ') size
+
+parseAlgo :: String -> Options -> Either String Options
+parseAlgo "None" o = Right $ o { algos = [] }
+parseAlgo "All"  o = Right $ o { algos = [DoNothing .. AmericanFlagSort] }
+parseAlgo s      o = leftMap (\e -> "Unrecognized algorithm `" ++ e ++ "'")
+                     . fmap (\v -> o { algos = v : algos o }) $ readEither s
+
+leftMap :: (a -> b) -> Either a c -> Either b c
+leftMap f (Left a)  = Left (f a)
+leftMap _ (Right c) = Right c
+
+parseNum :: (Int -> Options) -> String -> Either String Options
+parseNum f = leftMap (\e -> "Invalid numeric argument `" ++ e ++ "'") . fmap f . readEither
+
+parseN, parseK :: String -> Options -> Either String Options
+parseN s o = parseNum (\n -> o { elems   = n }) s
+parseK s o = parseNum (\k -> o { portion = k }) s
+
+readEither :: Read a => String -> Either String a
+readEither s = case reads s of
+  [(x,t)] | all isSpace t -> Right x
+  _                       -> Left s
+
+runTest :: GenIO -> Int -> Int -> Algorithm -> IO ()
+runTest g n k alg = case alg of
+  DoNothing          -> sortSuite        "no algorithm"          g n   noalgo
+  Allocate           -> sortSuite        "allocate"              g n   alloc
+  InsertionSort      -> sortSuite        "insertion sort"        g n   insertionSort
+  IntroSort          -> sortSuite        "introsort"             g n   introSort
+  IntroPartialSort   -> partialSortSuite "partial introsort"     g n k introPSort
+  IntroSelect        -> partialSortSuite "introselect"           g n k introSelect
+  HeapSort           -> sortSuite        "heap sort"             g n   heapSort
+  HeapPartialSort    -> partialSortSuite "partial heap sort"     g n k heapPSort
+  HeapSelect         -> partialSortSuite "heap select"           g n k heapSelect
+  MergeSort          -> sortSuite        "merge sort"            g n   mergeSort
+  RadixSort          -> sortSuite        "radix sort"            g n   radixSort
+  AmericanFlagSort   -> sortSuite        "flag sort"             g n   flagSort
+  TimSort            -> sortSuite        "tim sort"              g n   timSort
+  _                  -> putStrLn $ "Currently unsupported algorithm: " ++ show alg
+
+mergeSort :: MVector RealWorld Int -> IO ()
+mergeSort v = M.sort v
+{-# NOINLINE mergeSort #-}
+
+introSort :: MVector RealWorld Int -> IO ()
+introSort v = INT.sort v
+{-# NOINLINE introSort #-}
+
+introPSort :: MVector RealWorld Int -> Int -> IO ()
+introPSort v k = INT.partialSort v k
+{-# NOINLINE introPSort #-}
+
+introSelect :: MVector RealWorld Int -> Int -> IO ()
+introSelect v k = INT.select v k
+{-# NOINLINE introSelect #-}
+
+heapSort :: MVector RealWorld Int -> IO ()
+heapSort v = H.sort v
+{-# NOINLINE heapSort #-}
+
+heapPSort :: MVector RealWorld Int -> Int -> IO ()
+heapPSort v k = H.partialSort v k
+{-# NOINLINE heapPSort #-}
+
+heapSelect :: MVector RealWorld Int -> Int -> IO ()
+heapSelect v k = H.select v k
+{-# NOINLINE heapSelect #-}
+
+insertionSort :: MVector RealWorld Int -> IO ()
+insertionSort v = INS.sort v
+{-# NOINLINE insertionSort #-}
+
+radixSort :: MVector RealWorld Int -> IO ()
+radixSort v = R.sort v
+{-# NOINLINE radixSort #-}
+
+flagSort :: MVector RealWorld Int -> IO ()
+flagSort v = AF.sort v
+{-# NOINLINE flagSort #-}
+
+timSort :: MVector RealWorld Int -> IO ()
+timSort v = T.sort v
+{-# NOINLINE timSort #-}
+
+main :: IO ()
+main = getArgs >>= \args -> withSystemRandom $ \gen ->
+  case getOpt Permute options args of
+    (fs, _, []) -> case foldl (>>=) (Right defaultOptions) fs of
+      Left err   -> putStrLn $ usageInfo err options
+      Right opts | not (usage opts) ->
+        mapM_ (runTest gen (elems opts) (portion opts)) (algos opts)
+                 | otherwise -> putStrLn $ usageInfo "vector-algorithms-bench" options
+    (_, _, errs) -> putStrLn $ usageInfo (concat errs) options
+
+
diff --git a/src/Data/Vector/Algorithms/AmericanFlag.hs b/src/Data/Vector/Algorithms/AmericanFlag.hs
--- a/src/Data/Vector/Algorithms/AmericanFlag.hs
+++ b/src/Data/Vector/Algorithms/AmericanFlag.hs
@@ -36,6 +36,8 @@
 import Control.Monad
 import Control.Monad.Primitive
 
+import Data.Proxy
+
 import Data.Word
 import Data.Int
 import Data.Bits
@@ -51,31 +53,35 @@
 
 import qualified Data.Vector.Algorithms.Insertion as I
 
+import Foreign.Storable
+
 -- | The methods of this class specify the information necessary to sort
 -- arrays using the default ordering. The name 'Lexicographic' is meant
 -- to convey that index should return results in a similar way to indexing
 -- into a string.
 class Lexicographic e where
-  -- | Given a representative of a stripe and an index number, this
-  -- function should determine whether to stop sorting.
-  terminate :: e -> Int -> Bool
+  -- | Computes the length of a representative of a stripe. It should take 'n'
+  -- passes to sort values of extent 'n'. The extent may not be uniform across
+  -- all values of the type.
+  extent    :: e -> Int
+
   -- | The size of the bucket array necessary for sorting es
-  size      :: e -> Int
+  size      :: Proxy e -> Int
   -- | Determines which bucket a given element should inhabit for a
   -- particular iteration.
   index     :: Int -> e -> Int
 
 instance Lexicographic Word8 where
-  terminate _ n = n > 0
-  {-# INLINE terminate #-}
+  extent _ = 1
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index _ n = fromIntegral n
   {-# INLINE index #-}
 
 instance Lexicographic Word16 where
-  terminate _ n = n > 1
-  {-# INLINE terminate #-}
+  extent _ = 2
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ (n `shiftR`  8) .&. 255
@@ -84,8 +90,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic Word32 where
-  terminate _ n = n > 3
-  {-# INLINE terminate #-}
+  extent _ = 4
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ (n `shiftR` 24) .&. 255
@@ -96,8 +102,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic Word64 where
-  terminate _ n = n > 7
-  {-# INLINE terminate #-}
+  extent _ = 8
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ (n `shiftR` 56) .&. 255
@@ -112,8 +118,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic Word where
-  terminate _ n = n > 7
-  {-# INLINE terminate #-}
+  extent _ = sizeOf (0 :: Word)
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ (n `shiftR` 56) .&. 255
@@ -128,16 +134,16 @@
   {-# INLINE index #-}
 
 instance Lexicographic Int8 where
-  terminate _ n = n > 0
-  {-# INLINE terminate #-}
+  extent _ = 1
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index _ n = 255 .&. fromIntegral n `xor` 128
   {-# INLINE index #-}
 
 instance Lexicographic Int16 where
-  terminate _ n = n > 1
-  {-# INLINE terminate #-}
+  extent _ = 2
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ ((n `xor` minBound) `shiftR` 8) .&. 255
@@ -146,8 +152,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic Int32 where
-  terminate _ n = n > 3
-  {-# INLINE terminate #-}
+  extent _ = 4
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ ((n `xor` minBound) `shiftR` 24) .&. 255
@@ -158,8 +164,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic Int64 where
-  terminate _ n = n > 7
-  {-# INLINE terminate #-}
+  extent _ = 8
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = fromIntegral $ ((n `xor` minBound) `shiftR` 56) .&. 255
@@ -174,8 +180,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic Int where
-  terminate _ n = n > 7
-  {-# INLINE terminate #-}
+  extent _ = sizeOf (0 :: Int)
+  {-# INLINE extent #-}
   size _ = 256
   {-# INLINE size #-}
   index 0 n = ((n `xor` minBound) `shiftR` 56) .&. 255
@@ -190,8 +196,8 @@
   {-# INLINE index #-}
 
 instance Lexicographic B.ByteString where
-  terminate b i = i >= B.length b
-  {-# INLINE terminate #-}
+  extent = B.length
+  {-# INLINE extent #-}
   size _ = 257
   {-# INLINE size #-}
   index i b
@@ -199,15 +205,43 @@
     | otherwise       = fromIntegral (B.index b i) + 1
   {-# INLINE index #-}
 
+instance (Lexicographic a, Lexicographic b) => Lexicographic (a, b) where
+  extent (a,b) = extent a + extent b
+  {-# INLINE extent #-}
+  size _ = size (Proxy :: Proxy a) `max` size (Proxy :: Proxy b)
+  {-# INLINE size #-}
+  index i (a,b)
+    | i >= extent a = index i b
+    | otherwise     = index i a
+  {-# INLINE index #-}
+
+instance (Lexicographic a, Lexicographic b) => Lexicographic (Either a b) where
+  extent (Left  a) = 1 + extent a
+  extent (Right b) = 1 + extent b
+  {-# INLINE extent #-}
+  size _ = size (Proxy :: Proxy a) `max` size (Proxy :: Proxy b)
+  {-# INLINE size #-}
+  index 0 (Left  _) = 0
+  index 0 (Right _) = 1
+  index n (Left  a) = index (n-1) a
+  index n (Right b) = index (n-1) b
+  {-# INLINE index #-}
+
+-- | Given a representative of a stripe and an index number, this
+-- function determines whether to stop sorting.
+terminate :: Lexicographic e => e -> Int -> Bool
+terminate e i = i >= extent e
+{-# INLINE terminate #-}
+
 -- | Sorts an array using the default ordering. Both Lexicographic and
 -- Ord are necessary because the algorithm falls back to insertion sort
 -- for sufficiently small arrays.
 sort :: forall e m v. (PrimMonad m, MVector v e, Lexicographic e, Ord e)
      => v (PrimState m) e -> m ()
-sort v = sortBy compare terminate (size e) index v
- where e :: e
-       e = undefined
-{-# INLINE sort #-}
+sort v = sortBy compare terminate (size p) index v
+ where p :: Proxy e
+       p = Proxy
+{-# INLINABLE sort #-}
 
 -- | A fully parameterized version of the sorting algorithm. Again, this
 -- function takes both radix information and a comparison, because the
diff --git a/src/Data/Vector/Algorithms/Common.hs b/src/Data/Vector/Algorithms/Common.hs
--- a/src/Data/Vector/Algorithms/Common.hs
+++ b/src/Data/Vector/Algorithms/Common.hs
@@ -46,3 +46,13 @@
    | otherwise  = return ()
 {-# INLINE countLoop #-}
 
+midPoint :: Int -> Int -> Int
+midPoint a b =
+  toInt $ (toWord a + toWord b) `div` 2
+  where
+    toWord :: Int -> Word
+    toWord = fromIntegral
+
+    toInt :: Word -> Int
+    toInt = fromIntegral
+{-# INLINE midPoint #-}
diff --git a/src/Data/Vector/Algorithms/Heap.hs b/src/Data/Vector/Algorithms/Heap.hs
--- a/src/Data/Vector/Algorithms/Heap.hs
+++ b/src/Data/Vector/Algorithms/Heap.hs
@@ -54,7 +54,7 @@
 -- | Sorts an entire array using the default ordering.
 sort :: (PrimMonad m, MVector v e, Ord e) => v (PrimState m) e -> m ()
 sort = sortBy compare
-{-# INLINE sort #-}
+{-# INLINABLE sort #-}
 
 -- | Sorts an entire array using a custom ordering.
 sortBy :: (PrimMonad m, MVector v e) => Comparison e -> v (PrimState m) e -> m ()
diff --git a/src/Data/Vector/Algorithms/Insertion.hs b/src/Data/Vector/Algorithms/Insertion.hs
--- a/src/Data/Vector/Algorithms/Insertion.hs
+++ b/src/Data/Vector/Algorithms/Insertion.hs
@@ -34,7 +34,7 @@
 -- | Sorts an entire array using the default comparison for the type
 sort :: (PrimMonad m, MVector v e, Ord e) => v (PrimState m) e -> m ()
 sort = sortBy compare
-{-# INLINE sort #-}
+{-# INLINABLE sort #-}
 
 -- | Sorts an entire array using a given comparison
 sortBy :: (PrimMonad m, MVector v e) => Comparison e -> v (PrimState m) e -> m ()
diff --git a/src/Data/Vector/Algorithms/Intro.hs b/src/Data/Vector/Algorithms/Intro.hs
--- a/src/Data/Vector/Algorithms/Intro.hs
+++ b/src/Data/Vector/Algorithms/Intro.hs
@@ -56,7 +56,7 @@
 import Data.Bits
 import Data.Vector.Generic.Mutable
 
-import Data.Vector.Algorithms.Common (Comparison)
+import Data.Vector.Algorithms.Common (Comparison, midPoint)
 
 import qualified Data.Vector.Algorithms.Insertion as I
 import qualified Data.Vector.Algorithms.Optimal   as O
@@ -65,7 +65,7 @@
 -- | Sorts an entire array using the default ordering.
 sort :: (PrimMonad m, MVector v e, Ord e) => v (PrimState m) e -> m ()
 sort = sortBy compare
-{-# INLINE sort #-}
+{-# INLINABLE sort #-}
 
 -- | Sorts an entire array using a custom ordering.
 sortBy :: (PrimMonad m, MVector v e) => Comparison e -> v (PrimState m) e -> m ()
@@ -106,7 +106,7 @@
                     sort (d-1) l   (mid - 1)
   where
   len = u - l
-  c   = (u + l) `div` 2
+  c   = midPoint u l
 {-# INLINE introsort #-}
 
 -- | Moves the least k elements to the front of the array in
@@ -155,7 +155,7 @@
                    else if m < mid - 1
                         then go (n-1) l m (mid - 1)
                         else return ()
-  where c = (u + l) `div` 2
+  where c = midPoint u l
 {-# INLINE selectByBounds #-}
 
 -- | Moves the least k elements to the front of the array, sorted.
@@ -207,7 +207,7 @@
                                go (n-1) mid m u
                       EQ -> isort (n-1) l m
                       LT -> go n l m (mid - 1)
-  where c = (u + l) `div` 2
+  where c = midPoint u l
 {-# INLINE partialSortByBounds #-}
 
 partitionBy :: forall m v e. (PrimMonad m, MVector v e)
diff --git a/src/Data/Vector/Algorithms/Merge.hs b/src/Data/Vector/Algorithms/Merge.hs
--- a/src/Data/Vector/Algorithms/Merge.hs
+++ b/src/Data/Vector/Algorithms/Merge.hs
@@ -27,7 +27,7 @@
 import Data.Bits
 import Data.Vector.Generic.Mutable
 
-import Data.Vector.Algorithms.Common (Comparison, copyOffset)
+import Data.Vector.Algorithms.Common (Comparison, copyOffset, midPoint)
 
 import qualified Data.Vector.Algorithms.Optimal   as O
 import qualified Data.Vector.Algorithms.Insertion as I
@@ -35,7 +35,7 @@
 -- | Sorts an array using the default comparison.
 sort :: (PrimMonad m, MVector v e, Ord e) => v (PrimState m) e -> m ()
 sort = sortBy compare
-{-# INLINE sort #-}
+{-# INLINABLE sort #-}
 
 -- | Sorts an array using a custom comparison.
 sortBy :: (PrimMonad m, MVector v e) => Comparison e -> v (PrimState m) e -> m ()
@@ -60,7 +60,7 @@
                           loop mid u
                           merge cmp (unsafeSlice l len src) buf (mid - l)
   where len = u - l
-        mid = (u + l) `shiftR` 1
+        mid = midPoint u l
 {-# INLINE mergeSortWithBuf #-}
 
 merge :: (PrimMonad m, MVector v e)
diff --git a/src/Data/Vector/Algorithms/Radix.hs b/src/Data/Vector/Algorithms/Radix.hs
--- a/src/Data/Vector/Algorithms/Radix.hs
+++ b/src/Data/Vector/Algorithms/Radix.hs
@@ -186,7 +186,7 @@
  where
  e :: e
  e = undefined
-{-# INLINE sort #-}
+{-# INLINABLE sort #-}
 
 -- | Radix sorts an array using custom radix information
 -- requires the number of passes to fully sort the array,
diff --git a/src/Data/Vector/Algorithms/Search.hs b/src/Data/Vector/Algorithms/Search.hs
--- a/src/Data/Vector/Algorithms/Search.hs
+++ b/src/Data/Vector/Algorithms/Search.hs
@@ -39,7 +39,7 @@
 
 import Data.Vector.Generic.Mutable
 
-import Data.Vector.Algorithms.Common (Comparison)
+import Data.Vector.Algorithms.Common (Comparison, midPoint)
 
 -- | Finds an index in a given sorted vector at which the given element could
 -- be inserted while maintaining the sortedness of the vector.
@@ -70,7 +70,7 @@
                       LT -> loop (k+1) u
                       EQ -> return k
                       GT -> loop l     k
-  where k = (u + l) `shiftR` 1
+  where k = midPoint u l
 {-# INLINE binarySearchByBounds #-}
 
 -- | Finds the lowest index in a given sorted vector at which the given element
@@ -136,7 +136,7 @@
  loop !l !u
    | u <= l    = return l
    | otherwise = unsafeRead vec k >>= \e -> if p e then loop l k else loop (k+1) u
-  where k = (u + l) `shiftR` 1
+  where k = midPoint u l
 {-# INLINE binarySearchPBounds #-}
 
 -- | Given a predicate that is guaranteed to be monotone on the vector elements
diff --git a/tests/properties/Tests.hs b/tests/properties/Tests.hs
--- a/tests/properties/Tests.hs
+++ b/tests/properties/Tests.hs
@@ -117,15 +117,8 @@
 
 check_permutation = do
   qc $ label "introsort"    . prop_permutation (INT.sort :: Algo Int ())
-  qc $ label "intropartial" . prop_sized (const . prop_permutation)
-                                         (INT.partialSort :: SizeAlgo Int ())
-  qc $ label "introselect"  . prop_sized (const . prop_permutation)
-                                         (INT.select :: SizeAlgo Int ())
   qc $ label "heapsort"     . prop_permutation (H.sort :: Algo Int ())
-  qc $ label "heappartial"  . prop_sized (const . prop_permutation)
-                                         (H.partialSort :: SizeAlgo Int ())
-  qc $ label "heapselect"   . prop_sized (const . prop_permutation)
-                                         (H.select :: SizeAlgo Int ())
+
   qc $ label "mergesort"    . prop_permutation (M.sort :: Algo Int    ())
   qc $ label "timsort"      . prop_permutation (T.sort :: Algo Int    ())
   qc $ label "radix I8"     . prop_permutation (R.sort :: Algo Int8   ())
@@ -149,6 +142,17 @@
   qc $ label "flag W64"     . prop_permutation (AF.sort :: Algo Word64 ())
   qc $ label "flag Word"    . prop_permutation (AF.sort :: Algo Word   ())
   qc $ label "flag ByteString" . prop_permutation (AF.sort :: Algo B.ByteString ())
+{-
+  qc $ label "intropartial" . prop_sized (const . prop_permutation)
+                                         (INT.partialSort :: SizeAlgo Int ())
+  qc $ label "introselect"  . prop_sized (const . prop_permutation)
+                                         (INT.select :: SizeAlgo Int ())
+  qc $ label "heappartial"  . prop_sized (const . prop_permutation)
+                                         (H.partialSort :: SizeAlgo Int ())
+  qc $ label "heapselect"   . prop_sized (const . prop_permutation)
+                                         (H.select :: Algo Int ())
+-}
+
  where
  qc prop = quickCheckWith args prop
 
diff --git a/vector-algorithms.cabal b/vector-algorithms.cabal
--- a/vector-algorithms.cabal
+++ b/vector-algorithms.cabal
@@ -1,15 +1,17 @@
 name:              vector-algorithms
-version:           0.7.0.1
+version:           0.7.0.2
 license:           BSD3
 license-file:      LICENSE
 author:            Dan Doel
 maintainer:        Dan Doel <dan.doel@gmail.com>
+                   Erik de Castro Lopo <erikd@mega-nerd.com>
 copyright:         (c) 2008,2009,2010,2011,2012,2013,2014,2015 Dan Doel
                    (c) 2015 Tim Baumann
-homepage:          http://code.haskell.org/~dolio/
+homepage:          https://github.com/erikd/vector-algorithms/
 category:          Data
 synopsis:          Efficient algorithms for vector arrays
-description:       Efficient algorithms for vector arrays
+description:       Efficient algorithms for sorting vector arrays. At some stage
+                   other vector algorithms may be added.
 build-type:        Simple
 cabal-version:     >= 1.9.2
 
@@ -36,15 +38,23 @@
   description: Enable the quickcheck tests
   default: True
 
+-- flag dump-simpl
+--   description: Dumps the simplified core during compilation
+--   default: False
+
+flag llvm
+  description: Build using llvm
+  default: False
+
 source-repository head
-  type:     darcs
-  location: http://hub.darcs.net/dolio/vector-algorithms
+  type:     git
+  location: https://github.com/erikd/vector-algorithms/
 
 library
   hs-source-dirs: src
 
   build-depends: base >= 4.5 && < 5,
-                 vector >= 0.6 && < 0.12,
+                 vector >= 0.6 && < 0.13,
                  primitive >=0.3 && <0.7,
                  bytestring >= 0.9 && < 1.0
 
@@ -63,9 +73,15 @@
     Data.Vector.Algorithms.Common
 
   ghc-options:
-    -Odph
     -funbox-strict-fields
 
+  -- Cabal/Hackage complains about these
+  -- if flag(dump-simpl)
+  --   ghc-options: -ddump-simpl -ddump-to-file
+
+  if flag(llvm)
+    ghc-options: -fllvm
+
   include-dirs:
     include
 
@@ -81,8 +97,8 @@
   if flag(InternalChecks)
     cpp-options: -DVECTOR_INTERNAL_CHECKS
 
-executable vector-algorithms-bench
-  hs-source-dirs: bench
+executable simple-bench
+  hs-source-dirs: bench/simple
 
   if !flag(bench)
     buildable: False
@@ -93,8 +109,15 @@
     Blocks
 
   build-depends: base, mwc-random, vector, vector-algorithms, mtl
-  ghc-options: -Wall -Odph
+  ghc-options: -Wall
 
+  -- Cabal/Hackage complains about these
+  -- if flag(dump-simpl)
+  --   ghc-options: -ddump-simpl -ddump-to-file
+
+  if flag(llvm)
+    ghc-options: -fllvm
+
 test-suite properties
   hs-source-dirs: tests/properties
   type: exitcode-stdio-1.0
@@ -115,3 +138,6 @@
       QuickCheck >= 2,
       vector,
       vector-algorithms
+
+  if flag(llvm)
+    ghc-options: -fllvm
