diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright 2017 Clinton Mead
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
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/indextype.cabal b/indextype.cabal
new file mode 100644
--- /dev/null
+++ b/indextype.cabal
@@ -0,0 +1,38 @@
+name:                 indextype
+version:              0.1.0.0
+synopsis: A series of type families and constraints for "indexable" types.
+description:
+  This package deals with types that can roughly be "indexed" at compile time by an integer.
+  For example, tuples and be indexed by their nth elements, and functions by their nth argument.
+  A number of type functions allow one to extract these subtypes, i.e. the type of the 2nd element of a given tuple.
+
+  Furthermore, constraints are defined which allow one to easily constrain types to these index types,
+  e.g. a constraint that says "@t@ is a 3 tuple". @Control.IndexT@ has more detail.
+author:               Clinton Mead
+maintainer:           clintonmead@gmail.com
+category:             Control
+license: MIT
+license-file: LICENSE
+copyright: Clinton Mead (2017)
+build-type:           Simple
+cabal-version:        >=1.10
+tested-with: GHC == 8.0.2
+bug-reports:
+
+source-repository head
+  type: git
+  location: https://github.com/clintonmead/indextype.git
+
+library
+  exposed-modules:      Control.IndexT, Control.IndexT.Tuple, Control.IndexT.Function
+  build-depends:        base >= 4.7 && < 5
+  hs-source-dirs:       src
+  default-language:     Haskell2010
+
+Test-Suite tests
+  type: exitcode-stdio-1.0
+  main-is: Tests.hs
+  other-modules: Control.IndexT, Control.IndexT.Tuple, Control.IndexT.Function
+  build-depends:        base >= 4.7 && < 5, hspec
+  hs-source-dirs:       test, src
+  default-language:     Haskell2010
diff --git a/src/Control/IndexT.hs b/src/Control/IndexT.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/IndexT.hs
@@ -0,0 +1,221 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+
+{-|
+Module      : Control.IndexT
+Copyright   : Clinton Mead, 2017
+License     : MIT
+Maintainer  : clintonmead@gmail.com
+Stability   : experimental
+Portability : GHC
+
+This package is useful for dealing with for what I have called "indexed types". This is perhaps not a great choice of
+name (alternative suggestions welcome) but basically I'm talking about types where you can "index" them like an array.
+A tuple is a good example.
+
+This particular module gives you a type function 'IndexT' that allows you to get the type of the say, third
+element of a tuple.
+
+But the other modules in this package, "Control.IndexT.Tuple" and "Control.IndexT.Function", build on this.
+
+For example, occasionally you'll want to write a constraint like this:
+
+> t ~ (t1,t2)
+
+i.e. @t@ is a pair. But if @t1@ and @t2@ are not in scope, GHC will complain.
+
+This package contains some type family and class defined constraints that allow you to
+make constraints like "@t@ is a pair".
+
+The type families are open, so you can extend this
+module for your own data types.
+
+More detailed usage information is in the documentation, both below. and also in "Control.IndexT.Tuple".
+
+Currently this library deals with tuples up to length 15 and functions with up to 15 arguments.
+Let me know if you need anything bigger.
+-}
+
+module Control.IndexT (
+  IndexT
+  ) where
+
+import GHC.TypeLits (Nat)
+import GHC.Exts (Constraint)
+import Data.Functor.Identity (Identity)
+
+{-|
+'IndexT' is the core type family of this module. @IndexT n a@ gets the type of the "nth" element of @a@.
+In this module, 'IndexT' is defined on tuples and functions, and is zero based.
+
+So
+
+> IndexT 0 (a, b, c) == a
+
+and
+
+> IndexT 0 (a -> b -> c) == a
+
+Note the following:
+
+> IndexT 1 (a -> b -> c) == b
+> IndexT 2 (a, b, c) == c
+
+but...
+
+> IndexT 2 (a -> b -> c) /= c -- (it's actually not defined)
+
+This is because the way functions are defined. Consider a function of three arguments:
+
+> f :: a -> b -> c -> d
+
+For this function, we want:
+
+> IndexT 2 (a -> b -> c -> d) == c
+
+But if we defined 'IndexT' like the following:
+
+> IndexT 2 (a -> b -> c) = c
+
+Then we would find that:
+
+> IndexT 2 (a -> b -> c -> d) == IndexT 2 (a -> b -> (c -> d)) == (c -> d)
+
+Which is not right. For this reason, 'IndexT' can not get the "result" type of functions, you'll need to use 'ResultT' for that.
+-}
+type family IndexT (i :: Nat) a
+type instance IndexT 0 (Identity a) = a
+type instance IndexT 0 (a, _) = a
+type instance IndexT 1 (_, a) = a
+type instance IndexT 0 (a, _, _) = a
+type instance IndexT 1 (_, a, _) = a
+type instance IndexT 2 (_, _, a) = a
+type instance IndexT 0 (a, _, _, _) = a
+type instance IndexT 1 (_, a, _, _) = a
+type instance IndexT 2 (_, _, a, _) = a
+type instance IndexT 3 (_, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _) = a
+type instance IndexT 3 (_, _, _, a, _) = a
+type instance IndexT 4 (_, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _) = a
+type instance IndexT 5 (_, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a, _) = a
+type instance IndexT 9 (_, _, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _, _, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a, _, _) = a
+type instance IndexT 9 (_, _, _, _, _, _, _, _, _, a, _) = a
+type instance IndexT 10 (_, _, _, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _, _, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _, _, _, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a, _, _, _) = a
+type instance IndexT 9 (_, _, _, _, _, _, _, _, _, a, _, _) = a
+type instance IndexT 10 (_, _, _, _, _, _, _, _, _, _, a, _) = a
+type instance IndexT 11 (_, _, _, _, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _, _, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _, _, _, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _, _, _, _, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a, _, _, _, _) = a
+type instance IndexT 9 (_, _, _, _, _, _, _, _, _, a, _, _, _) = a
+type instance IndexT 10 (_, _, _, _, _, _, _, _, _, _, a, _, _) = a
+type instance IndexT 11 (_, _, _, _, _, _, _, _, _, _, _, a, _) = a
+type instance IndexT 12 (_, _, _, _, _, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _, _, _, _, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _, _, _, _, _, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a, _, _, _, _, _) = a
+type instance IndexT 9 (_, _, _, _, _, _, _, _, _, a, _, _, _, _) = a
+type instance IndexT 10 (_, _, _, _, _, _, _, _, _, _, a, _, _, _) = a
+type instance IndexT 11 (_, _, _, _, _, _, _, _, _, _, _, a, _, _) = a
+type instance IndexT 12 (_, _, _, _, _, _, _, _, _, _, _, _, a, _) = a
+type instance IndexT 13 (_, _, _, _, _, _, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 1 (_, a, _, _, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 2 (_, _, a, _, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 3 (_, _, _, a, _, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 4 (_, _, _, _, a, _, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 5 (_, _, _, _, _, a, _, _, _, _, _, _, _, _, _) = a
+type instance IndexT 6 (_, _, _, _, _, _, a, _, _, _, _, _, _, _, _) = a
+type instance IndexT 7 (_, _, _, _, _, _, _, a, _, _, _, _, _, _, _) = a
+type instance IndexT 8 (_, _, _, _, _, _, _, _, a, _, _, _, _, _, _) = a
+type instance IndexT 9 (_, _, _, _, _, _, _, _, _, a, _, _, _, _, _) = a
+type instance IndexT 10 (_, _, _, _, _, _, _, _, _, _, a, _, _, _, _) = a
+type instance IndexT 11 (_, _, _, _, _, _, _, _, _, _, _, a, _, _, _) = a
+type instance IndexT 12 (_, _, _, _, _, _, _, _, _, _, _, _, a, _, _) = a
+type instance IndexT 13 (_, _, _, _, _, _, _, _, _, _, _, _, _, a, _) = a
+type instance IndexT 14 (_, _, _, _, _, _, _, _, _, _, _, _, _, _, a) = a
+type instance IndexT 0 (a -> _) = a
+type instance IndexT 1 (_ -> a -> _) = a
+type instance IndexT 2 (_ -> _ -> a -> _) = a
+type instance IndexT 3 (_ -> _ -> _ -> a -> _) = a
+type instance IndexT 4 (_ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 5 (_ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 6 (_ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 7 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 8 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 9 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 10 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 11 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 12 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
+type instance IndexT 13 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a -> _) = a
diff --git a/src/Control/IndexT/Function.hs b/src/Control/IndexT/Function.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/IndexT/Function.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE UndecidableSuperClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+{-|
+Type family and class definitions for dealing with functions.
+
+Many of these definitions are similar to the ones that deal with tuples, in which case
+it refers to the documentation in "Control.IndexT.Tuple".
+
+Also see the "Control.IndexT" module description for an overview.
+-}
+
+
+module Control.IndexT.Function (
+  ResultT,
+  FuncN,
+  FuncConstraint,
+  HomoFuncConstraint,
+  HomoArgFuncConstraint,
+  IsFunc,
+  IsHomoFunc,
+  IsHomoArgFunc
+  )
+where
+
+import Control.IndexT (IndexT)
+
+import GHC.TypeLits (Nat)
+import GHC.Exts (Constraint)
+
+
+{-|
+'ResultT' is used to get the result type of functions, which 'IndexT' can not be used for as discussed in
+it's documentation.
+
+@ResultT n t@ gets the result of @t@ treated as an @n@ argument function. For example:
+
+> ResultT 2 (a -> b -> c) == c
+
+note that:
+
+> ResultT 2 (a -> b -> c -> d) == c -> d
+
+which makes sense, as the result of applying two arguments to this function is @(c -> d)@.
+-}
+type family ResultT (n :: Nat) a
+type instance ResultT 0 (a) = a
+type instance ResultT 1 (_ -> a) = a
+type instance ResultT 2 (_ -> _ -> a) = a
+type instance ResultT 3 (_ -> _ -> _ -> a) = a
+type instance ResultT 4 (_ -> _ -> _ -> _ -> a) = a
+type instance ResultT 5 (_ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 6 (_ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 7 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 8 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 9 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 10 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 11 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 12 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 13 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 14 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+type instance ResultT 15 (_ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> _ -> a) = a
+
+{-|
+Like 'Control.IndexT.TupleN', but for functions.
+-}
+type family FuncN (n :: Nat) a
+type instance FuncN 0 a = a
+type instance FuncN 1 a = IndexT 0 a -> ResultT 1 a
+type instance FuncN 2 a = IndexT 0 a -> IndexT 1 a -> ResultT 2 a
+type instance FuncN 3 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> ResultT 3 a
+type instance FuncN 4 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> ResultT 4 a
+type instance FuncN 5 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> ResultT 5 a
+type instance FuncN 6 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> ResultT 6 a
+type instance FuncN 7 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> ResultT 7 a
+type instance FuncN 8 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> ResultT 8 a
+type instance FuncN 9 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> ResultT 9 a
+type instance FuncN 10 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> IndexT 9 a -> ResultT 10 a
+type instance FuncN 11 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> IndexT 9 a -> IndexT 10 a -> ResultT 11 a
+type instance FuncN 12 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> IndexT 9 a -> IndexT 10 a -> IndexT 11 a -> ResultT 12 a
+type instance FuncN 13 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> IndexT 9 a -> IndexT 10 a -> IndexT 11 a -> IndexT 12 a -> ResultT 13 a
+type instance FuncN 14 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> IndexT 9 a -> IndexT 10 a -> IndexT 11 a -> IndexT 12 a -> IndexT 13 a -> ResultT 14 a
+type instance FuncN 15 a = IndexT 0 a -> IndexT 1 a -> IndexT 2 a -> IndexT 3 a -> IndexT 4 a -> IndexT 5 a -> IndexT 6 a -> IndexT 7 a -> IndexT 8 a -> IndexT 9 a -> IndexT 10 a -> IndexT 11 a -> IndexT 12 a -> IndexT 13 a -> IndexT 14 a -> ResultT 15 a
+
+{-|
+Like 'Control.IndexT.TupleConstraint', but for functions.
+-}
+type FuncConstraint (n :: Nat) a = a ~ FuncN n a
+
+{-|
+Like 'Control.IndexT.HomoTupleConstraint', but for functions, where all arguments and the result type are the same.
+-}
+type HomoFuncConstraint (n :: Nat) a = (HomoArgFuncConstraint n a, ResultT n a ~ IndexT 0 a)
+
+{-|
+Like 'HomoFuncConstraint', but only constrains all the arguments to be the same type, not the result.
+-}
+type family HomoArgFuncConstraint (n :: Nat) a :: Constraint
+type instance HomoArgFuncConstraint 0 a = (FuncConstraint 0 a)
+type instance HomoArgFuncConstraint 1 a = (FuncConstraint 1 a)
+type instance HomoArgFuncConstraint 2 a = (FuncConstraint 2 a, IndexT 0 a ~ IndexT 1 a)
+type instance HomoArgFuncConstraint 3 a = (FuncConstraint 3 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a)
+type instance HomoArgFuncConstraint 4 a = (FuncConstraint 4 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a)
+type instance HomoArgFuncConstraint 5 a = (FuncConstraint 5 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a)
+type instance HomoArgFuncConstraint 6 a = (FuncConstraint 6 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a)
+type instance HomoArgFuncConstraint 7 a = (FuncConstraint 7 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a)
+type instance HomoArgFuncConstraint 8 a = (FuncConstraint 8 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a)
+type instance HomoArgFuncConstraint 9 a = (FuncConstraint 9 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a)
+type instance HomoArgFuncConstraint 10 a = (FuncConstraint 10 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a)
+type instance HomoArgFuncConstraint 11 a = (FuncConstraint 11 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a)
+type instance HomoArgFuncConstraint 12 a = (FuncConstraint 12 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a)
+type instance HomoArgFuncConstraint 13 a = (FuncConstraint 13 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a, IndexT 11 a ~ IndexT 12 a)
+type instance HomoArgFuncConstraint 14 a = (FuncConstraint 14 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a, IndexT 11 a ~ IndexT 12 a, IndexT 12 a ~ IndexT 13 a)
+type instance HomoArgFuncConstraint 15 a = (FuncConstraint 15 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a, IndexT 11 a ~ IndexT 12 a, IndexT 12 a ~ IndexT 13 a, IndexT 13 a ~ IndexT 14 a)
+
+{-|
+Like 'Control.IndexT.IsTuple', but for functions.
+-}
+class (FuncConstraint n a) => IsFunc n a
+instance (FuncConstraint n a) => IsFunc n a
+
+{-|
+Like 'Control.IndexT.IsHomoTuple', but for functions.
+-}
+class (HomoFuncConstraint n a) => IsHomoFunc n a
+instance (HomoFuncConstraint n a) => IsHomoFunc n a
+
+{-|
+A classed based constraint for 'HomoArgFuncConstraint'.
+-}
+class (HomoArgFuncConstraint n a) => IsHomoArgFunc n a
+instance (HomoArgFuncConstraint n a) => IsHomoArgFunc n a
diff --git a/src/Control/IndexT/Tuple.hs b/src/Control/IndexT/Tuple.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/IndexT/Tuple.hs
@@ -0,0 +1,120 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE UndecidableSuperClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+{-|
+Type family and class definitions for dealing with tuples.
+
+See the "Control.IndexT" module description for an overview.
+-}
+
+module Control.IndexT.Tuple (
+  TupleN,
+  TupleConstraint,
+  HomoTupleConstraint,
+  IsTuple,
+  IsHomoTuple
+  )
+where
+
+import Control.IndexT (IndexT)
+
+import GHC.TypeLits (Nat)
+import GHC.Exts (Constraint)
+import Data.Functor.Identity (Identity)
+
+{-|
+'TupleN' seems a bit weird, but it's an important part of defining constraints that allow one to say "@t@ is a pair"
+in 'TupleConstraint'.
+-}
+type family TupleN (n :: Nat) a
+type instance TupleN 0 a = ()
+type instance TupleN 1 a = Identity a
+type instance TupleN 2 a = (IndexT 0 a, IndexT 1 a)
+type instance TupleN 3 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a)
+type instance TupleN 4 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a)
+type instance TupleN 5 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a)
+type instance TupleN 6 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a)
+type instance TupleN 7 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a)
+type instance TupleN 8 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a)
+type instance TupleN 9 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a)
+type instance TupleN 10 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a, IndexT 9 a)
+type instance TupleN 11 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a, IndexT 9 a, IndexT 10 a)
+type instance TupleN 12 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a, IndexT 9 a, IndexT 10 a, IndexT 11 a)
+type instance TupleN 13 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a, IndexT 9 a, IndexT 10 a, IndexT 11 a, IndexT 12 a)
+type instance TupleN 14 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a, IndexT 9 a, IndexT 10 a, IndexT 11 a, IndexT 12 a, IndexT 13 a)
+type instance TupleN 15 a = (IndexT 0 a, IndexT 1 a, IndexT 2 a, IndexT 3 a, IndexT 4 a, IndexT 5 a, IndexT 6 a, IndexT 7 a, IndexT 8 a, IndexT 9 a, IndexT 10 a, IndexT 11 a, IndexT 12 a, IndexT 13 a, IndexT 14 a)
+
+{-|
+To best explain this, lets consider the particular example @TupleConstraint 2@.
+
+As @TupleN 2 t = (IndexT 0 t, IndexT 1 t)@ we get:
+
+> TupleConstraint 2 t = t ~ (IndexT 0 t, IndexT 1 t)
+
+What does this say? Well, firstly, as @t ~ (IndexT 0 t, IndexT 1 t)@, it must be a pair at least.
+
+What are the elements of the pair? Well, the first element of @t@ is @IndexT 0 t@.
+
+And what's @IndexT 0 t@ defined as? The first element of @t@.
+
+So we know that the first element of @t@ is well, the first element of @t@.
+
+Which tells us nothing at all.
+
+We can go through the same argument with the second element of @t@.
+
+So all we know after this is that @t@ is a pair. @TupleConstraint 2 t@ is the same as saying @t@ is a pair.
+
+So @TupleConstraint n t@ basically says @t@ is a n-tuple.
+-}
+type TupleConstraint (n :: Nat) a = a ~ TupleN n a
+
+{-|
+'HomoTupleConstraint' simply further constrains 'TupleConstraint' so that all the elements are the same.
+
+So @HomoTupleConstraint 3 t@ basically says @t ~ (u,u,u)@ for some @u@,
+
+("Homo" is short for "Homogeneous". Like milk.)
+-}
+type family HomoTupleConstraint (n :: Nat) a :: Constraint
+type instance HomoTupleConstraint 0 a = (TupleConstraint 0 a)
+type instance HomoTupleConstraint 1 a = (TupleConstraint 1 a)
+type instance HomoTupleConstraint 2 a = (TupleConstraint 2 a, IndexT 0 a ~ IndexT 1 a)
+type instance HomoTupleConstraint 3 a = (TupleConstraint 3 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a)
+type instance HomoTupleConstraint 4 a = (TupleConstraint 4 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a)
+type instance HomoTupleConstraint 5 a = (TupleConstraint 5 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a)
+type instance HomoTupleConstraint 6 a = (TupleConstraint 6 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a)
+type instance HomoTupleConstraint 7 a = (TupleConstraint 7 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a)
+type instance HomoTupleConstraint 8 a = (TupleConstraint 8 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a)
+type instance HomoTupleConstraint 9 a = (TupleConstraint 9 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a)
+type instance HomoTupleConstraint 10 a = (TupleConstraint 10 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a)
+type instance HomoTupleConstraint 11 a = (TupleConstraint 11 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a)
+type instance HomoTupleConstraint 12 a = (TupleConstraint 12 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a)
+type instance HomoTupleConstraint 13 a = (TupleConstraint 13 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a, IndexT 11 a ~ IndexT 12 a)
+type instance HomoTupleConstraint 14 a = (TupleConstraint 14 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a, IndexT 11 a ~ IndexT 12 a, IndexT 12 a ~ IndexT 13 a)
+type instance HomoTupleConstraint 15 a = (TupleConstraint 15 a, IndexT 0 a ~ IndexT 1 a, IndexT 1 a ~ IndexT 2 a, IndexT 2 a ~ IndexT 3 a, IndexT 3 a ~ IndexT 4 a, IndexT 4 a ~ IndexT 5 a, IndexT 5 a ~ IndexT 6 a, IndexT 6 a ~ IndexT 7 a, IndexT 7 a ~ IndexT 8 a, IndexT 8 a ~ IndexT 9 a, IndexT 9 a ~ IndexT 10 a, IndexT 10 a ~ IndexT 11 a, IndexT 11 a ~ IndexT 12 a, IndexT 12 a ~ IndexT 13 a, IndexT 13 a ~ IndexT 14 a)
+
+{-|
+GHC does not allow you to partially apply type families (or any type declaration for that matter).
+So if you have a type of @* -> Constraint@ you can't pass @TupleConstraint 2@, because 'TupleConstraint' is partially
+applied and this is not allowed.
+
+But you can partially apply classes.
+
+So 'IsTuple' is basically the same as 'TupleConstraint' except that it's a class, not a type family.
+-}
+class (TupleConstraint n a) => IsTuple n a
+instance (TupleConstraint n a) => IsTuple n a
+
+{-|
+The version of 'IsTuple' for homogenous tuples (i.e. all the same type).
+-}
+class (HomoTupleConstraint n a) => IsHomoTuple n a
+instance (HomoTupleConstraint n a) => IsHomoTuple n a
+
diff --git a/test/Tests.hs b/test/Tests.hs
new file mode 100644
--- /dev/null
+++ b/test/Tests.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE PartialTypeSignatures #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Main where
+
+import Test.Hspec
+
+import Control.IndexT
+import Control.IndexT.Tuple
+import Control.IndexT.Function
+
+default ()
+
+data TT where
+  TT :: (forall t. (Integral (IndexT 0 t), Integral (IndexT 1 t), IsTuple 2 t) => t) -> TT
+
+data HTT where
+  HTT :: (forall t. (Num (IndexT 0 t), IsHomoTuple 2 t) => t) -> HTT
+
+data FT where
+  FT :: (forall t. (Num (IndexT 0 t), IndexT 1 t ~ Bool, IndexT 0 t ~ ResultT 2 t, IsFunc 2 t) => t) -> FT
+
+data HFT where
+  HFT :: (forall t. (Num (IndexT 0 t), IsHomoFunc 2 t) => t) -> HFT
+
+data HAFT where
+  HAFT :: (forall t. (Eq (IndexT 0 t), ResultT 2 t ~ Bool, IsHomoArgFunc 2 t) => t) -> HAFT
+
+f1 :: TT -> Integer
+f1 (TT (x :: (Int, Integer))) = toInteger (fst x) + toInteger (snd x)
+
+f2 :: Num a => HTT -> a
+f2 (HTT x) = fst x * snd x
+
+f3 :: (Num a) => FT -> a -> Bool -> a
+f3 (FT f) x y = f x y
+
+f4 :: (Num a) => HFT -> a -> a -> a
+f4 (HFT f) x y = f x y
+
+f5 :: (Eq a) => HAFT -> a -> a -> Bool
+f5 (HAFT f) x y = f x y
+
+x1 :: Integer
+x1 = f1 (TT (40,2))
+
+x2 :: Int
+x2 = f2 (HTT (12,7))
+
+x3 :: Int
+x3 = f3 (FT (\x y -> if y then x*2 else x*3)) 5 False
+
+x4 :: Integer
+x4 = f4 (HFT (+)) 40 3
+
+x5 :: Bool
+x5 = f5 (HAFT (==)) 'x' 'x'
+
+main :: IO ()
+main = hspec $ do
+  it "Tuple Test" $ x1 `shouldBe` 42
+  it "HomoTuple Test" $ x2 `shouldBe` 84
+  it "Func Test" $ x3 `shouldBe` 15
+  it "HomoFunc Test" $ x4 `shouldBe` 43
+  it "HomoArgFunc Test" $ x5 `shouldBe` True
