diff --git a/hw-prim.cabal b/hw-prim.cabal
--- a/hw-prim.cabal
+++ b/hw-prim.cabal
@@ -1,7 +1,7 @@
 cabal-version:  2.2
 
 name:           hw-prim
-version:        0.6.2.28
+version:        0.6.2.29
 synopsis:       Primitive functions and data types
 description:    Primitive functions and data types.
 category:       Data
diff --git a/src/HaskellWorks/Data/TreeCursor.hs b/src/HaskellWorks/Data/TreeCursor.hs
--- a/src/HaskellWorks/Data/TreeCursor.hs
+++ b/src/HaskellWorks/Data/TreeCursor.hs
@@ -1,8 +1,3 @@
--- |
--- Copyright: 2016 John Ky
--- License: MIT
---
--- Tree Cursor
 module HaskellWorks.Data.TreeCursor
     ( TreeCursor(..)
     ) where
diff --git a/src/HaskellWorks/Data/Vector/Storable.hs b/src/HaskellWorks/Data/Vector/Storable.hs
--- a/src/HaskellWorks/Data/Vector/Storable.hs
+++ b/src/HaskellWorks/Data/Vector/Storable.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE BangPatterns        #-}
+{-# LANGUAGE RankNTypes          #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 
 module HaskellWorks.Data.Vector.Storable
@@ -7,15 +8,17 @@
   , mapAccumL
   , mmap
   , constructSI
+  , construct2N
   ) where
 
-import Control.Monad.ST     (ST)
+import Control.Monad.ST     (ST, runST)
 import Data.Monoid          (Monoid (..), (<>))
 import Data.Vector.Storable (Storable)
 import Data.Word
 import Foreign.ForeignPtr
 import Prelude              hiding (foldMap)
 
+import qualified Data.Vector.Generic          as DVG
 import qualified Data.Vector.Storable         as DVS
 import qualified Data.Vector.Storable.Mutable as DVSM
 import qualified System.IO.MMap               as IO
@@ -69,3 +72,32 @@
             DVSM.unsafeWrite mv i a
             go (i + 1) s' mv
           else return s
+
+construct2N :: (Storable b, Storable c)
+  => Int
+  -> (forall s. a -> DVSM.MVector s b -> ST s Int)
+  -> Int
+  -> (forall s. a -> DVSM.MVector s c -> ST s Int)
+  -> [a]
+  -> (DVS.Vector b, DVS.Vector c)
+construct2N nb fb nc fc as = runST $ do
+  mbs <- DVSM.unsafeNew nb
+  mcs <- DVSM.unsafeNew nc
+  (mbs2, mcs2) <- go fb 0 mbs fc 0 mcs as
+  bs <- DVG.unsafeFreeze mbs2
+  cs <- DVG.unsafeFreeze mcs2
+  return (bs, cs)
+  where go :: (Storable b, Storable c)
+          => (forall t. a -> DVSM.MVector t b -> ST t Int)
+          -> Int
+          -> DVSM.MVector s b
+          -> (forall t. a -> DVSM.MVector t c -> ST t Int)
+          -> Int
+          -> DVSM.MVector s c
+          -> [a]
+          -> ST s (DVSM.MVector s b, DVSM.MVector s c)
+        go   _ bn mbs   _ cn mcs []     = return (DVSM.take bn mbs, DVSM.take cn mcs)
+        go fb' bn mbs fc' cn mcs (d:ds) = do
+          bi <- fb' d (DVSM.drop bn mbs)
+          ci <- fc' d (DVSM.drop cn mcs)
+          go fb' (bn + bi) mbs fc' (cn + ci) mcs ds
diff --git a/test/HaskellWorks/Data/Vector/StorableSpec.hs b/test/HaskellWorks/Data/Vector/StorableSpec.hs
--- a/test/HaskellWorks/Data/Vector/StorableSpec.hs
+++ b/test/HaskellWorks/Data/Vector/StorableSpec.hs
@@ -6,12 +6,15 @@
   ( spec
   ) where
 
+import Control.Monad.ST            (ST)
+import Data.Vector.Storable        (Storable)
 import HaskellWorks.Hspec.Hedgehog
 import Hedgehog
 import Test.Hspec
 
 import qualified Data.List                         as L
 import qualified Data.Vector.Storable              as DVS
+import qualified Data.Vector.Storable.Mutable      as DVSM
 import qualified HaskellWorks.Data.Vector.Storable as DVS
 import qualified Hedgehog.Gen                      as G
 import qualified Hedgehog.Range                    as R
@@ -28,3 +31,18 @@
     as <- forAll $ G.list (R.linear 0 10) (G.word64 (R.linear 0 255))
     let f a b = (a * 2, b + 1)
     (DVS.toList <$> DVS.mapAccumL f (0 :: Int) (DVS.fromList as)) === L.mapAccumL f (0 :: Int) as
+  it "construct2N" $ requireProperty $ do
+    as <- forAll $ G.list (R.linear 0 10) (G.word64 (R.linear 0 255))
+    let (bs, cs) = DVS.construct2N (length as) stepb (length as * 2) stepc as
+    DVS.fromList as           === bs
+    DVS.fromList (dupList as) === cs
+
+dupList :: [a] -> [a]
+dupList (a:as) = (a:a:dupList as)
+dupList []     = []
+
+stepb :: Storable a => a -> DVSM.MVector s a -> ST s Int
+stepb a v = DVSM.write v 0 a >> return 1
+
+stepc :: Storable a => a -> DVSM.MVector s a -> ST s Int
+stepc a v = DVSM.write v 0 a >> DVSM.write v 1 a >> return 2
