diff --git a/Data/Array/Parallel/Unlifted.hs b/Data/Array/Parallel/Unlifted.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted.hs
@@ -0,0 +1,97 @@
+{-# LANGUAGE CPP #-}
+
+-- | Primitive sequential combinators that work on flat, unlifted arrays.
+--
+--   This set of combinators is used when the program is compiled with @-fdph-seq@.
+--   When compiling with @-fdph-par@, the ones in the @dph-prim-par package@ are used
+--   instead. The @dph-prim-par package@ exports the same names, but all combinators
+--   are implemented sequentially.
+--
+--   The API is defined in @DPH_Header.h@ and @DPH_Interface.h@ to ensure that both
+--   @dph-prim-par@ and @dph-prim-seq@ really do export the same symbols.
+
+#include "DPH_Header.h"
+
+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector as V
+import Data.Array.Parallel.Unlifted.Sequential.USel
+import Data.Array.Parallel.Unlifted.Sequential.Segmented
+
+#include "DPH_Interface.h"
+
+class V.Unbox a => Elt a
+type Array              = V.Vector
+type Segd               = USegd
+type Sel2               = USel2
+type SelRep2            = ()
+
+length                  = V.length
+empty                   = V.empty
+replicate               = V.replicate
+repeat n _              = V.repeat n
+(!:)                    = (V.!)
+extract                 = V.extract
+drop                    = V.drop
+permute                 = V.permute
+bpermute                = V.bpermute
+mbpermute               = V.mbpermute
+bpermuteDft             = V.bpermuteDft
+update                  = V.update
+(+:+)                   = (V.++)
+interleave              = V.interleave
+pack                    = V.pack
+combine                 = V.combine
+combine2 tags _         = V.combine2ByTag tags
+map                     = V.map
+filter                  = V.filter
+zip                     = V.zip
+unzip                   = V.unzip
+fsts                    = V.fsts
+snds                    = V.snds
+zipWith                 = V.zipWith
+fold                    = V.fold
+fold1                   = V.fold1
+and                     = V.and
+sum                     = V.sum
+scan                    = V.scan
+indexed                 = V.indexed
+enumFromTo              = V.enumFromTo
+enumFromThenTo          = V.enumFromThenTo
+enumFromStepLen         = V.enumFromStepLen
+enumFromStepLenEach     = V.enumFromStepLenEach
+
+mkSel2 tags idxs n0 n1 _ = mkUSel2 tags idxs n0 n1
+tagsSel2                = tagsUSel2
+indicesSel2             = indicesUSel2
+elementsSel2_0          = elementsUSel2_0
+elementsSel2_1          = elementsUSel2_1
+repSel2 _               = ()
+
+mkSelRep2 tags          = ()
+indicesSelRep2 tags _   = tagsToIndices2 tags
+elementsSelRep2_0 tags _ = count tags 0
+elementsSelRep2_1 tags _ = count tags 1
+
+replicate_s             = replicateSU
+replicate_rs            = replicateRSU
+append_s _              = appendSU
+fold_s                  = foldSU
+fold1_s                 = fold1SU
+fold_r                  = foldlRU
+sum_r                   = sumRU
+
+indices_s               = indicesSU
+
+lengthSegd              = lengthUSegd
+lengthsSegd             = lengthsUSegd
+indicesSegd             = indicesUSegd
+elementsSegd            = elementsUSegd
+mkSegd                  = mkUSegd
+randoms                 = V.random
+randomRs                = V.randomR
+
+class V.UIO a => IOElt a
+hPut                    = V.hPut
+hGet                    = V.hGet
+toList                  = V.toList
+fromList                = V.fromList
+
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Segmented.hs b/Data/Array/Parallel/Unlifted/Sequential/Segmented.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Segmented.hs
@@ -0,0 +1,27 @@
+-- | Interface to operations on segmented unlifted arrays.
+module Data.Array.Parallel.Unlifted.Sequential.Segmented (
+
+  replicateSU, replicateRSU, appendSU, indicesSU, indicesSU',
+
+  foldlSU, foldSU, fold1SU,
+  foldlRU,
+  combineSU,
+
+  -- * Logical operations
+  andSU, orSU,
+
+  -- * Arithmetic operations
+  sumSU, productSU, maximumSU, minimumSU,
+  sumRU,
+  USegd,
+
+  -- * Operations on segment descriptors
+  lengthUSegd, lengthsUSegd, indicesUSegd, elementsUSegd,
+  lengthsToUSegd, mkUSegd
+) where
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.Basics
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.Combinators
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.Sums
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.Text ()
+
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Segmented/Basics.hs b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Basics.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Basics.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE CPP #-}
+#include "fusion-phases.h"
+
+-- | Basic segmented operations on unlifted arrays.
+module Data.Array.Parallel.Unlifted.Sequential.Segmented.Basics (
+  replicateSU, replicateRSU, appendSU, indicesSU, indicesSU'
+) where
+import Data.Array.Parallel.Stream
+import Data.Array.Parallel.Unlifted.Sequential.Vector
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd
+import qualified Data.Vector.Fusion.Stream as S
+
+
+replicateSU :: Unbox a => USegd -> Vector a -> Vector a
+{-# INLINE_U replicateSU #-}
+replicateSU segd xs = unstream
+                     (replicateEachS (elementsUSegd segd)
+                     (S.zip (stream (lengthsUSegd segd)) (stream xs)))
+
+
+replicateRSU :: Unbox a => Int -> Vector a -> Vector a
+{-# INLINE_U replicateRSU #-}
+replicateRSU n xs = unstream
+                  . replicateEachRS n
+                  $ stream xs
+                  
+
+appendSU :: Unbox a => USegd -> Vector a -> USegd -> Vector a -> Vector a
+{-# INLINE_U appendSU #-}
+appendSU xd xs yd ys = unstream
+                     $ appendSS (stream (lengthsUSegd xd))
+                                (stream xs)
+                                (stream (lengthsUSegd yd))
+                                (stream ys)
+
+
+indicesSU' :: Int -> USegd -> Vector Int
+{-# INLINE_U indicesSU' #-}
+indicesSU' i segd = unstream
+                  . indicesSS (elementsUSegd segd) i
+                  . stream
+                  $ lengthsUSegd segd
+
+
+indicesSU :: USegd -> Vector Int
+{-# INLINE_U indicesSU #-}
+indicesSU = indicesSU' 0
+
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Segmented/Combinators.hs b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Combinators.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Combinators.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE CPP #-}
+#include "fusion-phases.h"
+
+-- | Standard combinators for segmented unlifted arrays.
+module Data.Array.Parallel.Unlifted.Sequential.Segmented.Combinators (
+  foldlSU, foldSU, foldl1SU, fold1SU, {-scanSU,-} {-scan1SU,-}
+  foldlRU,
+  combineSU
+) where
+import Data.Array.Parallel.Stream (
+  foldSS, fold1SS, combineSS, foldValuesR )
+import Data.Array.Parallel.Unlifted.Sequential.Vector as V
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd
+import Debug.Trace
+
+
+-- | Segmented array reduction proceeding from the left
+foldlSU :: (Unbox a, Unbox b) => (b -> a -> b) -> b -> USegd -> Vector a -> Vector b
+{-# INLINE_U foldlSU #-}
+foldlSU f z segd xs = unstream
+                    $ foldSS f z (stream (lengthsUSegd segd)) (stream xs)
+
+
+-- | Segmented array reduction that requires an associative combination
+--   function with its unit
+foldSU :: Unbox a => (a -> a -> a) -> a -> USegd -> Vector a -> Vector a
+foldSU = foldlSU
+
+
+-- | Segmented array reduction from left to right with non-empty subarrays only
+foldl1SU :: Unbox a => (a -> a -> a) -> USegd -> Vector a -> Vector a
+{-# INLINE_U foldl1SU #-}
+foldl1SU f segd xs = unstream
+                   $ fold1SS f (stream (lengthsUSegd segd)) (stream xs)
+
+
+-- | Segmented array reduction with non-empty subarrays and an associative
+--   combination function
+fold1SU :: Unbox a => (a -> a -> a) -> USegd -> Vector a -> Vector a
+fold1SU = foldl1SU
+
+
+-- | Merge two segmented arrays according to flag array
+combineSU :: Unbox a => Vector Bool -> USegd -> Vector a -> USegd -> Vector a -> Vector a
+{-# INLINE_U combineSU #-}
+combineSU bs xd xs yd ys = unstream
+                         $ combineSS (stream bs)
+                                     (stream (lengthsUSegd xd)) (stream xs)
+                                     (stream (lengthsUSegd yd)) (stream ys)
+
+
+-- | Regular arrar reduction 
+foldlRU :: (Unbox a, Unbox b) => (b -> a -> b) -> b -> Int -> Vector a -> Vector b
+{-# INLINE_U foldlRU #-}
+foldlRU f z segSize = unstream . foldValuesR f z segSize . stream
+
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Segmented/Sums.hs b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Sums.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Sums.hs
@@ -0,0 +1,50 @@
+-- | Sum-like operations on segmented list-like combinators.
+module Data.Array.Parallel.Unlifted.Sequential.Segmented.Sums (
+  andSU, orSU, sumSU, productSU, maximumSU, minimumSU,
+  sumRU
+) where
+import Data.Array.Parallel.Unlifted.Sequential.Vector as V
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd (
+  USegd )
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.Combinators (
+  foldSU, fold1SU, foldlRU)
+
+
+-- | Compute the boolean AND of all segments in a segmented array.
+andSU :: USegd -> Vector Bool -> Vector Bool
+andSU = foldSU (&&) True
+
+
+-- | Compute the boolean OR of all segments in a segmented array.
+orSU :: USegd -> Vector Bool -> Vector Bool
+orSU = foldSU (||) False
+
+
+-- | Compute the segmented sum of an array of numerals
+sumSU :: (Num e, Unbox e) => USegd -> Vector e -> Vector e
+{-# INLINE sumSU #-}
+sumSU = foldSU (+) 0
+
+
+-- | Compute the segmented product of an array of numerals
+productSU :: (Num e, Unbox e) => USegd -> Vector e -> Vector e
+{-# INLINE productSU #-}
+productSU = foldSU (*) 1
+
+
+-- | Determine the maximum element in each subarray
+maximumSU :: (Ord e, Unbox e) => USegd -> Vector e -> Vector e
+{-# INLINE maximumSU #-}
+maximumSU = fold1SU max
+
+
+-- | Determine the minimum element in each subarray
+minimumSU :: (Ord e, Unbox e) => USegd -> Vector e -> Vector e
+{-# INLINE minimumSU #-}
+minimumSU = fold1SU min
+
+
+-- | Compute the segmented sum of an array of numerals
+sumRU :: (Num e, Unbox e) => Int ->Vector e -> Vector e
+{-# INLINE sumRU #-}
+sumRU = foldlRU (+) 0
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Segmented/Text.hs b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Text.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Segmented/Text.hs
@@ -0,0 +1,11 @@
+-- | Read\/Show instances for segmented unlifted arrays.
+module Data.Array.Parallel.Unlifted.Sequential.Segmented.Text ()
+where
+import Data.Array.Parallel.Base (
+  Read(..), showsApp, readApp)
+import Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd (
+  USegd, lengthsUSegd )
+
+instance Show USegd where
+  showsPrec k = showsApp k "toUSegd" . lengthsUSegd
+
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Segmented/USegd.hs b/Data/Array/Parallel/Unlifted/Sequential/Segmented/USegd.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Segmented/USegd.hs
@@ -0,0 +1,137 @@
+{-# LANGUAGE CPP #-}
+#include "fusion-phases.h"
+
+-- | Segment Descriptors
+module Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd (
+  -- * Types
+  USegd,
+
+  -- * Constructors
+  mkUSegd,
+  emptyUSegd, singletonUSegd, lengthsToUSegd,
+
+  -- * Projections
+  lengthUSegd, lengthsUSegd, indicesUSegd, elementsUSegd, 
+
+  -- * Operations
+  sliceUSegd, extractUSegd
+) where
+import Data.Array.Parallel.Unlifted.Sequential.Vector as V
+
+-- | Segment descriptors represent the structure of nested arrays.
+--  For each segment, it stores the length and the starting index in the flat data array.
+--
+--   Example:
+--
+--   @
+--    flat array data:  [1, 2, 3, 4, 5, 6, 7, 8]
+--      (segmentation)   ----  -------  -  ----
+--      segd  lengths: [2, 3, 1, 2]
+--            indices: [0, 2, 5, 6]
+--           elements: 8 
+--   @
+data USegd 
+        = USegd 
+        { usegd_lengths  :: !(Vector Int)  -- ^ length of each segment
+        , usegd_indices  :: !(Vector Int)  -- ^ starting index of each segment in the flat array
+        , usegd_elements :: !Int           -- ^ total number of elements in the flat array
+        }
+
+
+-- Constructors ---------------------------------------------------------------
+-- | O(1). Construct a new segment descriptor.
+mkUSegd 
+        :: Vector Int   -- ^ length of each segment
+        -> Vector Int   -- ^ starting index of each segment
+        -> Int          -- ^ total number of elements in the flat array
+        -> USegd
+
+{-# INLINE mkUSegd #-}
+mkUSegd = USegd
+
+
+-- | O(1). Yield an empty segment descriptor, with no elements or segments.
+emptyUSegd :: USegd
+{-# INLINE emptyUSegd #-}
+emptyUSegd = USegd V.empty V.empty 0
+
+
+-- | O(1). Yield a singleton segment descriptor.
+--         The single segment covers the given number of elements.
+singletonUSegd :: Int -> USegd
+{-# INLINE singletonUSegd #-}
+singletonUSegd n = USegd (V.singleton n) (V.singleton 0) n
+
+
+-- | O(n). Convert a length array into a segment descriptor.
+-- 
+--   The array contains the length of each segment, and we compute the 
+--   indices from that. Runtime is O(n) in the number of segments.
+--
+lengthsToUSegd :: Vector Int -> USegd
+{-# INLINE lengthsToUSegd #-}
+lengthsToUSegd lens
+        = USegd lens (V.scanl (+) 0 lens) (V.sum lens)
+
+
+-- Projections ----------------------------------------------------------------
+-- | O(1). Yield the overall number of segments.
+lengthUSegd :: USegd -> Int
+{-# INLINE lengthUSegd #-}
+lengthUSegd = V.length . usegd_lengths
+
+
+-- | O(1). Yield the lengths of the individual segments.
+lengthsUSegd :: USegd -> Vector Int
+{-# INLINE lengthsUSegd #-}
+lengthsUSegd = usegd_lengths
+
+
+-- | O(1). Yield the segment indices of a segment descriptor.
+indicesUSegd :: USegd -> Vector Int
+{-# INLINE indicesUSegd #-}
+indicesUSegd = usegd_indices
+
+
+-- | O(1). Yield the number of data elements.
+elementsUSegd :: USegd -> Int
+{-# INLINE elementsUSegd #-}
+elementsUSegd = usegd_elements
+
+
+-- | O(n). Extract a slice of a segment descriptor, avoiding copying where possible.
+--
+--   We can share the segment lengths with the original segment descriptor, 
+--   but still need to recompute the starting indices of each. Hence
+--   runtime is O(n) in the number of segments sliced out.
+-- 
+--   NOTE: In the new segment descriptor, the starting index of the first
+--         segment will be 0.
+sliceUSegd 
+        :: USegd        -- ^ source segment descriptor
+        -> Int          -- ^ index of first segment
+        -> Int          -- ^ number of segments to slice out
+        -> USegd
+        
+{-# INLINE sliceUSegd #-}
+sliceUSegd segd i n
+        = lengthsToUSegd $ V.slice (lengthsUSegd segd) i n
+
+
+-- | O(n). Extract a slice of a segment descriptor, copying everything.
+--
+--   In contrast to `sliceUSegd`, this function copies the array of 
+--   segment lengths as well as recomputing the starting indices of each.
+--
+--   NOTE: In the new segment descriptor, the starting index of the first
+--         segment will be 0.
+extractUSegd 
+        :: USegd        -- ^ source segment desciptor
+        -> Int          -- ^ index of the first segment
+        -> Int          -- ^ number of segments to extract out
+        -> USegd
+
+{-# INLINE extractUSegd #-}
+extractUSegd segd i n 
+        = lengthsToUSegd $ V.extract (lengthsUSegd segd) i n
+
diff --git a/Data/Array/Parallel/Unlifted/Sequential/USel.hs b/Data/Array/Parallel/Unlifted/Sequential/USel.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/USel.hs
@@ -0,0 +1,122 @@
+-- | A selector is a description of how to perform a `combine` operation.
+--
+-- Suppose we are evaluating the following expression:
+--
+--   @combine [F,F,T,F,T,T] [1,2,3] [4,5,6] = [4,5,1,6,2,3]@
+--
+-- This is difficult to parallelise. For each element in the result, the source 
+-- array we get this element from depends on the tag values associated with 
+-- all previous elements.
+--
+-- However, if we going to perform several combines with the same tag array, we
+-- can precompute a selector that tells us where to get each element. The selector
+-- contains the original tags, as well as the source index telling us where to get
+-- each element for the result array.
+--
+-- For example:
+--
+--  @
+--  tagsToIndices2 [F,F,T,F,T,T]   -- tags
+--               = [0,1,0,2,1,2]   -- indices
+--  @
+--
+--  This says get the first element from index 0 in the second array, then from index 1 in the second array,
+--  then index 0 in the first array ...
+--  
+--  The selector then consists of both the @tag@ and @indices@ arrays.
+--
+{-# LANGUAGE CPP #-}
+
+#include "fusion-phases.h"
+
+module Data.Array.Parallel.Unlifted.Sequential.USel (
+  -- * Types
+  USel2,
+
+  -- * Operations on selectors
+  mkUSel2,
+  lengthUSel2,
+  tagsUSel2, indicesUSel2, elementsUSel2_0, elementsUSel2_1,
+  tagsToIndices2
+) where
+import Data.Array.Parallel.Unlifted.Sequential.Vector as V
+import qualified Data.Vector.Fusion.Stream as S
+import Data.Vector.Fusion.Stream.Monadic ( Stream(..) )
+import Data.Array.Parallel.Base (Tag)
+
+
+-- | Abstract selector. 
+--   Contains both the @tags@ and @indices@ arrays outlined above.
+data USel2 
+        = USel2
+        { usel2_tags      :: !(Vector Tag)
+        , usel2_indices   :: !(Vector Int)
+        , usel2_elements0 :: !Int               -- ^ number of tags with value 0
+        , usel2_elements1 :: !Int               -- ^ number of tags with value 1
+        }
+
+
+-- | O(1). Construct a selector.
+mkUSel2 :: Vector Tag           -- ^ tags array 
+        -> Vector Int           -- ^ indices array
+        -> Int                  -- ^ number of elements taken from first array
+        -> Int                  -- ^ number of elements taken from second array
+        -> USel2
+{-# INLINE mkUSel2 #-}
+mkUSel2 = USel2
+
+
+-- | O(1). Get the number of elements represented by this selector.
+--         This is the length of the array returned by `combine`.
+lengthUSel2 :: USel2 -> Int
+{-# INLINE lengthUSel2 #-}
+lengthUSel2 = V.length . usel2_tags
+
+
+-- | O(1). Get the tags array of a selector.
+tagsUSel2 :: USel2 -> Vector Tag
+{-# INLINE tagsUSel2 #-}
+tagsUSel2 = usel2_tags
+
+
+-- | O(1). Get the indices array of a selector.
+indicesUSel2 :: USel2 -> Vector Int
+{-# INLINE indicesUSel2 #-}
+indicesUSel2 = usel2_indices
+
+
+-- | O(1). Get the number of elements that will be taken from the first array.
+elementsUSel2_0 :: USel2 -> Int
+{-# INLINE elementsUSel2_0 #-}
+elementsUSel2_0 = usel2_elements0
+
+
+-- | O(1). Get the number of elements that will be taken from the second array.
+elementsUSel2_1 :: USel2 -> Int
+{-# INLINE elementsUSel2_1 #-}
+elementsUSel2_1 = usel2_elements1
+
+
+-- | O(n). Compute the source index for each element of the result array.
+tagsToIndices2 :: Vector Tag -> Vector Int
+{-# INLINE tagsToIndices2 #-}
+tagsToIndices2 tags 
+  = unstream (mapAccumS add (0,0) (stream tags))
+  where
+    add (i,j) 0 = ((i+1,j),i)
+    add (i,j) _ = ((i,j+1),j)
+
+
+mapAccumS :: (acc -> a -> (acc,b)) -> acc -> S.Stream a -> S.Stream b
+{-# INLINE_STREAM mapAccumS #-}
+mapAccumS f acc (Stream step s n)
+  = Stream step' (acc,s) n
+  where
+   {-# INLINE_INNER step' #-}
+   step' (acc,s) 
+    = do r <- step s
+         case r of
+          S.Yield x s' -> let (acc',y) = f acc x
+                          in return $ S.Yield y (acc',s')
+          S.Skip    s' -> return $ S.Skip (acc,s')
+          S.Done       -> return S.Done
diff --git a/Data/Array/Parallel/Unlifted/Sequential/Vector.hs b/Data/Array/Parallel/Unlifted/Sequential/Vector.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Parallel/Unlifted/Sequential/Vector.hs
@@ -0,0 +1,472 @@
+{-# LANGUAGE ScopedTypeVariables, BangPatterns, CPP #-}
+
+#include "fusion-phases.h"
+
+-- | Wrappers for primitives defined in @Data.Vector@
+module Data.Array.Parallel.Unlifted.Sequential.Vector (
+
+  -- * Array classes
+  Unbox,
+
+  -- * Array types
+  Vector, MVector,
+
+  -- * Streaming
+  stream, unstream,
+
+  -- * Basic operations
+  length, null, empty, singleton, cons, units,
+  replicate,
+  -- replicateEachU,
+  (!), (++),
+  interleave, indexed, repeat, repeatS,
+
+  -- * Subarrays
+  slice, extract,
+  tail,
+  take, drop, splitAt,
+
+  -- * Permutations
+  permute, bpermute, mbpermute, bpermuteDft, reverse, update,
+
+
+  -- * Higher-order operations
+  map, zipWith, zipWith3,
+  filter, pack, 
+  combine, combine2ByTag,
+  foldl, foldl1, foldl1Maybe,
+  fold, fold1, fold1Maybe,
+  scanl, scanl1,
+  scan, scan1,
+  scanRes,
+
+  -- * Searching
+  elem, notElem,
+
+  -- * Logical operations
+  and, or, any, all,
+
+  -- * Arithmetic operations
+  sum, product,
+  maximum, minimum,
+  maximumBy, minimumBy,
+  maxIndex, minIndex,
+  maxIndexBy, minIndexBy,
+
+  -- * Arrays of pairs
+  zip, unzip, fsts, snds,
+
+  -- * Enumerations
+  enumFromTo, enumFromThenTo, enumFromStepLen, enumFromToEach, enumFromStepLenEach,
+
+  -- * Searching
+  find, findIndex,
+
+  -- * Conversions to\/from lists
+  toList, fromList,
+
+  -- * Random arrays
+  random, randomR,
+
+  -- * Mutating operations
+  new, copy,
+
+  -- * Mutable vectors
+  newM, unsafeFreeze, M.write, M.read, mpermute, mupdate,
+  mdrop, mslice,
+
+  -- * I\/O
+  UIO(..)
+
+) where
+
+import Data.Array.Parallel.Stream
+import Data.Array.Parallel.Base ( Tag, checkEq, ST )
+
+import Data.Vector.Unboxed hiding ( slice, zip, unzip, foldl, foldl1, scanl, scanl1 )
+import qualified Data.Vector.Unboxed as V
+import qualified Data.Vector.Unboxed.Mutable as M
+import qualified Data.Vector.Unboxed.Base as VBase
+import Data.Vector.Generic ( stream, unstream )
+import qualified Data.Vector.Generic as G
+import qualified Data.Vector.Generic.Mutable as MG
+import qualified Data.Vector.Storable as Storable
+import qualified Data.Vector.Storable.Mutable as MStorable
+import qualified Data.Vector.Generic.New as New
+import qualified Data.Vector.Fusion.Stream as S
+import Data.Vector.Fusion.Stream.Monadic ( Stream(..), Step(..) )
+import Data.Vector.Fusion.Stream.Size ( Size(..) )
+import Prelude hiding ( length, null,
+                        replicate, (++), repeat,
+                        tail, take, drop, splitAt,
+                        reverse,
+                        map, zipWith, zipWith3, filter,
+                        foldl, foldl1, scanl, scanl1,
+                        elem, notElem,
+                        and, or, any, all,
+                        sum, product,
+                        maximum, minimum,
+                        zip, unzip,
+                        enumFromTo, enumFromThenTo )
+import qualified Prelude
+import qualified System.Random as R
+import Foreign hiding ( new )
+import System.IO
+
+here s = "Data.Array.Parallel.Unlifted.Sequential.Flat." Prelude.++ s
+
+
+new :: Unbox a => Int -> (forall s. MVector s a -> ST s ()) -> Vector a
+{-# INLINE new #-}
+new n p = V.create (do
+                      v <- M.new n
+                      p v
+                      return v)
+
+
+newM :: Unbox a => Int -> ST s (MVector s a)
+{-# INLINE newM #-}
+newM = M.new
+
+
+-- | Yield an array of units 
+units :: Int -> Vector ()
+{-# INLINE units #-}
+units n = replicate n ()
+                        
+
+-- | Interleave the elements of two arrays
+interleave :: Unbox e => Vector e -> Vector e -> Vector e
+{-# INLINE_U interleave #-}
+interleave xs ys = unstream (interleaveS (stream xs) (stream ys))
+
+
+-- | Repeat an array @n@ times
+repeat :: Unbox e => Int -> Vector e -> Vector e
+{-# INLINE_U repeat #-}
+repeat n xs = unstream (repeatS n xs)
+
+
+repeatS :: Unbox e => Int -> Vector e -> S.Stream e
+{-# INLINE_STREAM repeatS #-}
+repeatS k !xs = Stream next (0,k) (Exact (k*n))
+  where
+    !n = length xs
+
+    {-# INLINE next #-}
+    next (i,0) = return Done
+    next (i,k) | i == n    = return $ Skip                     (0,k-1)
+               | otherwise = return $ Yield (unsafeIndex xs i) (i+1,k)
+
+
+slice :: Unbox a => Vector a -> Int -> Int -> Vector a
+{-# INLINE_U slice #-}
+slice xs i n = V.slice i n xs
+
+
+extract :: Unbox a => Vector a -> Int -> Int -> Vector a
+{-# INLINE_U extract #-}
+extract xs i n = force (V.slice i n xs)
+
+
+mupdate :: Unbox e => MVector s e -> Vector (Int,e) -> ST s ()
+{-# INLINE_U mupdate #-}
+mupdate marr xs = MG.update marr (stream xs)
+
+
+mpermute :: Unbox e => MVector s e -> Vector e -> Vector Int -> ST s ()
+{-# INLINE_U mpermute #-}
+mpermute marr xs is = MG.update marr (stream (zip is xs))
+
+
+permute :: Unbox e => Vector e -> Vector Int -> Vector e
+{-# INLINE_U permute #-}
+permute xs is = create (do
+                          v <- M.new (length xs)
+                          mpermute v xs is
+                          return v)
+
+
+bpermute :: Unbox e => Vector e -> Vector Int -> Vector e
+{-# INLINE_U bpermute #-}
+bpermute = backpermute
+
+
+mbpermute :: (Unbox e, Unbox d) => (e -> d) -> Vector e -> Vector Int -> Vector d
+{-# INLINE_STREAM mbpermute #-}
+mbpermute f es is  = unstream (mbpermuteS f es (stream is))
+
+
+bpermuteS :: Unbox e => Vector e -> S.Stream Int -> S.Stream e
+{-# INLINE_STREAM bpermuteS #-}
+bpermuteS !a s = S.map (a!) s
+
+
+mbpermuteS:: Unbox e => (e -> d) -> Vector e -> S.Stream Int -> S.Stream d
+{-# INLINE_STREAM mbpermuteS #-}
+mbpermuteS f !a = S.map (f . (a!))
+
+
+-- | Default back permute
+--
+-- * The values of the index-value pairs are written into the position in the
+--   result array that is indicated by the corresponding index.
+--
+-- * All positions not covered by the index-value pairs will have the value
+--   determined by the initialiser function for that index position.
+--
+bpermuteDft :: Unbox e
+	    => Int			        -- ^ length of result array
+	    -> (Int -> e)		        -- ^ initialiser function
+	    -> Vector (Int,e)	        	-- ^ index-value pairs
+	    -> Vector e
+{-# INLINE_U bpermuteDft #-}
+bpermuteDft n init = update (map init (enumFromN 0 n))
+
+
+-- | Extract all elements from an array according to a given flag array
+pack:: Unbox e => Vector e -> Vector Bool -> Vector e
+{-# INLINE_U pack #-}
+pack xs = map fst . filter snd . zip xs
+
+
+combine :: Unbox a
+	 => Vector Bool -> Vector a -> Vector a -> Vector a
+{-# INLINE combine #-}
+combine bs = combine2ByTag (map (\b -> if b then 0 else 1) bs)
+
+
+combine2ByTag :: Unbox a => Vector Tag -> Vector a -> Vector a -> Vector a
+{-# INLINE_U combine2ByTag #-}
+combine2ByTag ts xs ys
+  = checkEq (here "combine2ByTag")
+            ("tags length /= sum of args length")
+            (length ts) (length xs + length ys)
+  $ unstream (combine2ByTagS (stream ts) (stream xs) (stream ys))
+
+
+-- | Array reduction proceeding from the left
+foldl :: Unbox a => (b -> a -> b) -> b -> Vector a -> b
+{-# INLINE_U foldl #-}
+foldl = foldl'
+
+
+-- | Array reduction proceeding from the left for non-empty arrays
+foldl1 :: Unbox a => (a -> a -> a) -> Vector a -> a
+{-# INLINE_U foldl1 #-}
+foldl1 = foldl1'
+
+-- | Array reduction that requires an associative combination function with its
+--   unit
+fold :: Unbox a => (a -> a -> a) -> a -> Vector a -> a
+{-# INLINE_U fold #-}
+fold = foldl
+
+
+-- | Reduction of a non-empty array which requires an associative combination
+--   function
+fold1 :: Unbox a => (a -> a -> a) -> Vector a -> a
+{-# INLINE_U fold1 #-}
+fold1 = foldl1
+
+
+foldl1Maybe :: Unbox a => (a -> a -> a) -> Vector a -> Maybe a
+{-# INLINE_U foldl1Maybe #-}
+foldl1Maybe f xs = foldl' join Nothing xs
+  where
+    {-# INLINE join #-}
+    join Nothing  y = Just $! y
+    join (Just x) y = Just $! f x y
+
+
+fold1Maybe :: Unbox a => (a -> a -> a) -> Vector a -> Maybe a
+{-# INLINE_U fold1Maybe #-}
+fold1Maybe = foldl1Maybe
+
+-- | Prefix scan proceedings from left to right
+scanl :: (Unbox a, Unbox b) => (b -> a -> b) -> b -> Vector a -> Vector b
+{-# INLINE_U scanl #-}
+scanl = prescanl'
+
+
+-- | Prefix scan of a non-empty array proceeding from left to right
+scanl1 :: Unbox a => (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE_U scanl1 #-}
+scanl1 = scanl1'
+
+
+-- | Prefix scan proceeding from left to right that needs an associative
+--   combination function with its unit
+scan :: Unbox a => (a -> a -> a) -> a -> Vector a -> Vector a
+{-# INLINE_U scan #-}
+scan = scanl
+
+
+-- | Prefix scan of a non-empty array proceeding from left to right that needs
+--   an associative combination function
+scan1 :: Unbox a => (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE_U scan1 #-}
+scan1 = scanl1
+
+
+scanRes :: Unbox a => (a -> a -> a) -> a -> Vector a -> (Vector a,a)
+{-# INLINE_U scanRes #-}
+scanRes f z xs = let ys = scanl' f z xs
+                 in
+                 (unsafeInit ys, unsafeLast ys)
+
+
+fsts :: (Unbox a, Unbox b) => Vector (a,b) -> Vector a
+{-# INLINE_STREAM fsts #-}
+fsts (VBase.V_2 _ xs ys) = xs
+
+
+snds :: (Unbox a, Unbox b) => Vector (a,b) -> Vector b
+{-# INLINE_STREAM snds #-}
+snds (VBase.V_2 _ xs ys) = ys
+
+
+zip :: (Unbox a, Unbox b) => Vector a -> Vector b -> Vector (a,b)
+{-# INLINE_STREAM zip #-}
+zip !xs !ys = V.zip xs ys
+
+
+unzip :: (Unbox a, Unbox b) => Vector (a,b) -> (Vector a, Vector b)
+{-# INLINE_STREAM unzip #-}
+unzip ps = V.unzip ps
+
+{-# RULES
+
+"fsts/new/unstream [dph-prim-seq]" forall xs.
+  fsts (G.new (New.unstream xs)) = V.map fst (G.new (New.unstream xs))
+
+"snds/new/unstream [dph-prim-seq]" forall xs.
+  snds (G.new (New.unstream xs)) = V.map snd (G.new (New.unstream xs))
+
+"stream/zip [dph-prim-seq]" forall xs ys.
+  G.stream (zip xs ys) = S.zip (G.stream xs) (G.stream ys)
+
+  #-}
+
+
+enumFromStepLen :: Int -> Int -> Int -> Vector Int
+{-# INLINE_U enumFromStepLen #-}
+enumFromStepLen = enumFromStepN
+
+
+enumFromToEach :: Int -> Vector (Int,Int) -> Vector Int
+{-# INLINE_U enumFromToEach #-}
+enumFromToEach n = unstream . enumFromToEachS n . stream
+
+
+enumFromStepLenEach :: Int -> Vector Int -> Vector Int -> Vector Int -> Vector Int
+{-# INLINE_U enumFromStepLenEach #-}
+enumFromStepLenEach len starts steps lens
+  = unstream $ enumFromStepLenEachS len $ stream $ V.zip3 starts steps lens
+
+
+random :: (Unbox a, R.Random a, R.RandomGen g) => Int -> g -> Vector a
+{-# INLINE_U random #-}
+random n = unstream . randomS n
+
+
+randomR :: (Unbox a, R.Random a, R.RandomGen g) => Int -> (a,a) -> g -> Vector a
+{-# INLINE_U randomR #-}
+randomR n r = unstream . randomRS n r
+
+
+randomS :: (R.RandomGen g, R.Random a) => Int -> g -> S.Stream a
+{-# INLINE_STREAM randomS #-}
+randomS n g = Stream step (g,n) (Exact n)
+  where
+    {-# INLINE step #-}
+    step (g,0) = return Done
+    step (g,n) = let (x,g') = R.random g
+                 in return $ Yield x (g',n-1)
+
+
+randomRS :: (R.RandomGen g, R.Random a) => Int -> (a,a) -> g -> S.Stream a
+{-# INLINE_STREAM randomRS #-}
+randomRS n r g = Stream step (g,n) (Exact n)
+  where
+    {-# INLINE step #-}
+    step (g,0) = return Done
+    step (g,n) = let (x,g') = R.randomR r g
+                 in return $ Yield x (g',n-1)
+
+
+mdrop :: Unbox a => Int -> MVector s a -> MVector s a
+{-# INLINE mdrop #-}
+mdrop = M.drop
+
+
+mslice :: Unbox a => Int -> Int -> MVector s a -> MVector s a
+{-# INLINE mslice #-}
+mslice = M.slice
+
+
+hGetStorable :: forall a. Storable a => Handle -> IO (Storable.Vector a)
+hGetStorable h =
+  alloca $ \iptr ->
+  do
+    hGetBuf h iptr (sizeOf (undefined :: Int))
+    n <- peek iptr
+    v <- MStorable.unsafeNew n
+    let bytes = sizeOf (undefined :: a) * MStorable.length v
+    r <- MStorable.unsafeWith v $ \ptr -> hGetBuf h ptr bytes
+    Storable.unsafeFreeze (MStorable.take r v)
+
+
+hPutStorable :: forall a. Storable a => Handle -> Storable.Vector a -> IO ()
+hPutStorable h xs =
+  alloca $ \iptr ->
+  do
+    poke iptr n 
+    hPutBuf h iptr (sizeOf n)
+    Storable.unsafeWith xs $ \ptr ->
+      do
+        hPutBuf h ptr (sizeOf (undefined :: a) * n)
+        return ()
+  where
+    !n = Storable.length xs
+
+class Unbox a => UIO a where
+  hPut :: Handle -> Vector a -> IO ()
+  hGet :: Handle -> IO (Vector a)
+
+
+primPut :: (Unbox a, Storable a) => Handle -> Vector a -> IO ()
+{-# INLINE primPut #-}
+primPut h = hPutStorable h . Storable.convert
+
+
+primGet :: (Unbox a, Storable a) => Handle -> IO (Vector a)
+{-# INLINE primGet #-}
+primGet = fmap convert . hGetStorable
+
+
+instance UIO Int where
+  {-# INLINE hPut #-}
+  hPut = primPut
+  {-# INLINE hGet #-}
+  hGet = primGet
+
+
+instance UIO Double where
+  {-# INLINE hPut #-}
+  hPut = primPut
+  {-# INLINE hGet #-}
+  hGet = primGet
+
+
+instance (UIO a, UIO b) => UIO (a,b) where
+  {-# INLINE hPut #-}
+  hPut h xs = case V.unzip xs of
+                (ys,zs) -> do hPut h ys
+                              hPut h zs
+
+  {-# INLINE hGet #-}
+  hGet h = do xs <- hGet h
+              ys <- hGet h
+              return (V.zip xs ys)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,37 @@
+Copyright (c) 2001-2011, The DPH Team
+All rights reserved.
+
+The DPH Team is:
+  Manuel M T Chakravarty
+  Gabriele Keller
+  Roman Leshchinskiy
+  Ben Lippmeier
+  George Roldugin
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+ 
+- Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+ 
+- Neither name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
+GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/dph-prim-seq.cabal b/dph-prim-seq.cabal
new file mode 100644
--- /dev/null
+++ b/dph-prim-seq.cabal
@@ -0,0 +1,38 @@
+Name:           dph-prim-seq
+Version:        0.5.1.1
+License:        BSD3
+License-File:   LICENSE
+Author:         The DPH Team
+Maintainer:     Ben Lippmeier <benl@cse.unsw.edu.au>
+Homepage:       http://www.haskell.org/haskellwiki/GHC/Data_Parallel_Haskell
+Category:       Data Structures
+Synopsis:       Sequential Primitives for Data-Parallel Haskell.
+
+Cabal-Version:  >= 1.6
+Build-Type:     Simple
+
+Library
+  Exposed-Modules:
+        Data.Array.Parallel.Unlifted.Sequential.Segmented
+        Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd
+        Data.Array.Parallel.Unlifted.Sequential.Vector
+        Data.Array.Parallel.Unlifted.Sequential.USel
+        Data.Array.Parallel.Unlifted
+  Other-Modules:
+        Data.Array.Parallel.Unlifted.Sequential.Segmented.Basics
+        Data.Array.Parallel.Unlifted.Sequential.Segmented.Combinators
+        Data.Array.Parallel.Unlifted.Sequential.Segmented.Sums
+        Data.Array.Parallel.Unlifted.Sequential.Segmented.Text
+
+  Exposed: False
+
+  Extensions: TypeFamilies, GADTs, RankNTypes,
+              BangPatterns, MagicHash, UnboxedTuples, TypeOperators
+  GHC-Options: -Odph -funbox-strict-fields -fcpr-off
+
+  Build-Depends:  
+        base     == 4.4.*,
+        random   == 1.0.*,
+        vector   == 0.7.*,
+        dph-base == 0.5.*,
+        dph-prim-interface == 0.5.*
