diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2017
+
+All rights reserved.
+
+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 the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 COPYRIGHT
+OWNER OR 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# n-tuple
+
+
+```haskell
+{-# LANGUAGE DataKinds -#}
+
+import Data.NTuple
+
+
+foo :: NTuple 3 String
+foo
+  = incl _3 "three"
+  . incl _2 "two"
+  . incl _1 "one"
+  $ empty
+
+
+one :: String
+one = proj _1 foo
+
+two :: String
+two = proj _2 foo
+```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/n-tuple.cabal b/n-tuple.cabal
new file mode 100644
--- /dev/null
+++ b/n-tuple.cabal
@@ -0,0 +1,26 @@
+name:                n-tuple
+version:             0.0.0
+synopsis:            Homogeneous tuples of arbitrary length.
+-- description:
+homepage:            https://github.com/athanclark/n-tuple#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Athan Clark
+maintainer:          athan.clark@gmail.com
+copyright:           2017 Athan Clark
+category:            Data
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Data.NTuple
+  build-depends:       base >= 4.7 && < 5
+                     , singletons
+                     , vector
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/athanclark/n-tuple
diff --git a/src/Data/NTuple.hs b/src/Data/NTuple.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/NTuple.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE
+    DataKinds
+  , TypeOperators
+  , KindSignatures
+  , PolyKinds
+  , TypeFamilies
+  #-}
+
+module Data.NTuple
+  ( NTuple
+  , empty
+  , proj
+  , incl
+  , -- * Proxies
+    _1
+  , _2
+  , _3
+  , _4
+  , _5
+  , _6
+  , _7
+  , _8
+  , _9
+  , _10
+  ) where
+
+import Data.Vector (Vector, (!))
+import qualified Data.Vector as V
+
+import GHC.TypeLits
+import Data.Proxy (Proxy)
+import Data.List (intercalate)
+import Data.Singletons.Prelude
+import Data.Singletons.Prelude.Ord
+
+
+newtype NTuple (size :: Nat) a = NTuple
+  { getNTuple :: Vector a
+  }
+
+
+instance Show a => Show (NTuple size a) where
+  show (NTuple xs) = "( " ++ intercalate ", " (V.toList (show <$> xs)) ++ ")"
+
+
+empty :: NTuple 0 a
+empty = NTuple V.empty
+
+
+proj :: ( n <= size
+        , (n :> 0) ~ True
+        , KnownNat n
+        )
+      => Proxy n
+      -> NTuple size a
+      -> a
+proj p (NTuple xs) = xs V.! (fromInteger (natVal p) - 1)
+
+
+incl :: ( n <= (size + 1)
+        , (n :> 0) ~ True
+        , KnownNat n
+        , size' ~ If (n :== (size + 1)) (size + 1) size
+        )
+     => Proxy n
+     -> a
+     -> NTuple size a
+     -> NTuple size' a
+incl p x (NTuple xs) = NTuple $
+  let n = fromInteger (natVal p) - 1
+      (l,r) = V.splitAt n xs
+
+  in  l V.++ (x `V.cons` (tail' r))
+  where
+    tail' r
+      | V.null r  = V.empty
+      | otherwise = V.tail r
+
+
+
+
+_1 :: Proxy 1
+_1 = Proxy
+
+_2 :: Proxy 2
+_2 = Proxy
+
+_3 :: Proxy 3
+_3 = Proxy
+
+_4 :: Proxy 4
+_4 = Proxy
+
+_5 :: Proxy 5
+_5 = Proxy
+
+_6 :: Proxy 6
+_6 = Proxy
+
+_7 :: Proxy 7
+_7 = Proxy
+
+_8 :: Proxy 8
+_8 = Proxy
+
+_9 :: Proxy 9
+_9 = Proxy
+
+_10 :: Proxy 10
+_10 = Proxy
