diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for data-combinator-gen
+
+## 0.1.0.0 -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2019 Armando Santos
+
+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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+# Data Combinator Generator
+
+Generate a special combinator from any data type.
+
+## Description
+
+This library provides a function to generate a special combinator from any data
+type (GADTs are not currently supported).
+
+This was inspired by the recursion-schemes library where they have a function to
+automagically generate a base functor. Although, this new base functor data type
+has custom constructors and to define the \*-morphism algebras turns into
+boring pattern matching.
+
+So, this library provides a function called `makeCombinator` that produces a
+nice combinator to deal with data types as they were defined in terms of Pairs
+(`(,)`) and Sums (`Either`). With this nice combinator we are able to view a
+data type as its equivalent categorical isomorphism and manipulate it with an
+interface similar as the `either` function provided from `base`.
+
+## Example
+
+To create this special combinator you just need to call `makeCombinator ''<data
+type name>` as in the example below:
+
+```Haskell
+
+-- List type
+data List a = Nil | List a (List a)
+
+makeCombinator ''List
+```
+
+This example will generate the following code:
+
+```Haskell
+makeCombinator ''ListF
+  ======>
+    listf f_acw7 f_acw8 Nil = f_acw7 ()
+    listf f_acw7 f_acw8 (Cons a_acw9 a_acwa) = f_acw8 (a_acw9, a_acwa)
+```
+
+As you can see it's pretty close as to have the type defined as the set of
+sums and pairs `data List a = Either () (a, List a)`, which we could then use
+`either` function as well as other convinent `(,)` combinators.
+
+An **important** note is that the generated function has always the same name as
+the data type but in low characters **and** the order of the functions to be
+applied to the type constructors it's the same order which they were declared.
+
+A simple example on how we can beneficiate from using this special combinator
+when defining catamorphisms using recursion-schemes:
+
+- Without the combinator:
+  ```Haskell
+  length :: [a] -> Int
+  length = cata gene
+    where
+      gene Nil = 0
+      gene (Cons a x) = x + 1
+  ```
+
+- With the combinator:
+  ```Haskell
+  makeCombinator'' ListF
+
+  length :: [a] -> Int
+  length = cata (listf (const 0) (succ . snd))
+  ```
+
+I recognize that for such a simple data type and catamorphism it's hard to see
+any gain in readability/implementation. But with this special combinator it's a
+lot easier to go from paper to code as it's almost a direct translation.
+
+There's a fully working example in the `examples` folder that uses the
+recursion-schemes library as well as a nice small program calculus (AoP
+inspired) combinators library to show how simple and straightforward it is to
+use it with this new combinator.
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/data-combinator-gen.cabal b/data-combinator-gen.cabal
new file mode 100644
--- /dev/null
+++ b/data-combinator-gen.cabal
@@ -0,0 +1,86 @@
+cabal-version:       >=1.10
+
+-- Initial package description 'data-combinator-gen.cabal' generated by
+-- 'cabal init'.  For further documentation, see
+-- http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                data-combinator-gen
+
+-- The package version.  See the Haskell package versioning policy (PVP)
+-- for standards guiding when and how versions should be incremented.
+-- https://pvp.haskell.org
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:            Generate a special combinator from any data type.
+
+-- A longer description of the package.
+description: 
+  This library provides a function to generate a special combinator from any data type (GADTs are not currently supported).
+
+  This was inspired by the recursion-schemes library where they have a function to automagically generate a base functor. Although, this new base functor data type has custom constructors and to define the *-morphism algebras turns into boring pattern matching.
+
+  So, this library provides a function called `makeCombinator` that produces a
+  nice combinator to deal with data types as they were defined in terms of Pairs
+  ( (,) ) and Sums (`Either`). With this nice combinator we are able to view a
+  data type as its equivalent categorical isomorphism and manipulate it with an
+  interface similar as the `either` function provided from `base`.
+
+-- URL for the project homepage or repository.
+homepage:            https://github.com/bolt12/data-combinator-gen
+
+-- A URL where users can report bugs.
+-- bug-reports:
+
+-- The license under which the package is released.
+license:             MIT
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Armando Santos
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer:          armandoifsantos@gmail.com
+
+-- A copyright notice.
+-- copyright:
+
+category:            Data
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a
+-- README.
+extra-source-files:  CHANGELOG.md,
+                     README.md,
+                     examples/Cp.hs,
+                     examples/Main.hs
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules: Data.Combinators.TH
+
+  -- Modules included in this library but not exported.
+  -- other-modules:
+
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:
+
+  -- Other library packages from which modules are imported.
+  build-depends:       base >=4.12 && <4.13,
+                       template-haskell >= 2.5.0.0 && < 2.16
+
+  -- Directories containing source files.
+  hs-source-dirs:      src
+
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+
diff --git a/examples/Cp.hs b/examples/Cp.hs
new file mode 100644
--- /dev/null
+++ b/examples/Cp.hs
@@ -0,0 +1,273 @@
+{-# LANGUAGE TypeOperators #-}
+
+-- (c) MP-I (1998/9-2006/7) and CP (2005/6-2017/8)
+
+module Cp where
+
+infixl 4  ><
+infixl 5  -|-
+
+-- (1) Product -----------------------------------------------------------------
+
+-- Type alias
+type a >< b = (a, b)
+
+split :: (a -> b) -> (a -> c) -> a -> b >< c
+split f g x = (f x, g x)
+
+(><) :: (a -> b) -> (c -> d) -> a >< c -> b >< d
+f >< g = split (f . p1) (g . p2)
+
+-- the 0-adic split 
+
+(!) :: a -> ()
+(!) = const ()
+
+-- Renamings:
+
+p1 :: a >< b -> a
+p1 = fst
+
+p2 :: a >< b -> b
+p2 = snd
+
+-- (2) Coproduct ---------------------------------------------------------------
+
+-- Type alias
+
+type a -|- b = Either a b
+
+-- Renamings:
+
+i1 :: a -> a -|- b
+i1 = Left
+
+i2 :: b -> a -|- b
+i2 = Right
+
+-- either is predefined
+
+(-|-) :: (a -> b) -> (c -> d) -> a -|- c -> b -|- d
+f -|- g = either (i1 . f) (i2 . g)
+
+-- McCarthy's conditional:
+
+cond :: (b -> Bool) -> (b -> c) -> (b -> c) -> b -> c
+cond p f g = either f g . grd p
+
+-- (3) Exponentiation ---------------------------------------------------------
+
+-- curry is predefined
+
+ap :: (a -> b) >< a -> b
+ap = uncurry ($)
+
+expn :: (b -> c) -> (a -> b) -> a -> c
+expn f = curry (f . ap)
+
+p2p :: a >< a -> Bool -> a
+p2p p b = if b then snd p else fst p -- pair to predicate
+
+-- exponentiation functor is (a->) predefined 
+
+-- instance Functor ((->) s) where
+--	fmap f g = f . g
+
+-- (4) Others -----------------------------------------------------------------
+
+--const :: a -> b -> a st const a x = a is predefined
+
+grd :: (a -> Bool) -> a -> a -|- a
+grd p x = if p x then Left x else Right x
+
+-- (5) Natural isomorphisms ----------------------------------------------------
+
+swap :: a >< b -> b >< a
+swap = split p2 p1
+
+assocr :: ((a >< b) >< c) -> (a >< (b >< c))
+assocr = split (p1 . p1) (p2 >< id)
+
+assocl :: (a >< (b >< c)) -> ((a >< b) >< c)
+assocl = split (id >< p1) (p2 . p2)
+
+undistr :: (a >< b) -|- (a >< c) -> a >< (b -|- c)
+undistr = either (id >< i1) (id >< i2)
+
+undistl :: (b >< c) -|- (a >< c) -> (b -|- a) >< c
+undistl = either (i1 >< id) (i2 >< id)
+
+flatr :: (a >< (b >< c)) -> (a, b, c)
+flatr (a, (b, c)) = (a, b, c)
+
+flatl :: ((a >< b) >< c) -> (a, b, c)
+flatl ((b, c), d) = (b, c, d)
+
+-- pwnil = split id (!)
+
+br :: a -> a >< ()
+br = split id (!) -- bang on the right, old pwnil means "pair with nil"
+
+bl :: a -> () >< a
+bl = swap . br
+
+coswap :: a -|- b -> b -|- a
+coswap = either i2 i1
+
+coassocr :: ((a -|- b) -|- c) -> (a -|- (b -|- c))
+coassocr = either (id -|- i1) (i2 . i2)
+
+coassocl :: (b -|- (a -|- c)) -> ((b -|- a) -|- c)
+coassocl = either (i1 . i1) (i2 -|- id)
+
+distl :: ((c -|- a) >< b) -> (c >< b) -|- (a >< b)
+distl = uncurry (either (curry i1) (curry i2))
+
+distr :: (b >< c -|- a) -> (b >< c) -|- (b >< a)
+distr = (swap -|- swap) . distl . swap
+
+-- (6) Class bifunctor ---------------------------------------------------------
+
+class BiFunctor f where
+      bmap :: (a -> b) -> (c -> d) -> (f a c -> f b d)
+
+instance BiFunctor Either where
+    bmap f g = f -|- g
+
+instance BiFunctor (,) where
+    bmap f g  = f >< g
+
+-- (7) Monads: -----------------------------------------------------------------
+
+-- (7.1) Kleisli monadic composition -------------------------------------------
+
+infix 4  .!
+
+(.!) :: Monad a => (b -> a c) -> (d -> a b) -> d -> a c
+(f .! g) a = g a >>= f
+
+mult :: (Monad m) => m (m b) -> m b
+-- also known as join
+mult = (>>= id)
+
+-- (7.2) Monadic binding ---------------------------------------------------------
+
+ap' :: (Monad m) => (a -> m b, m a) -> m b
+ap' = uncurry (=<<)
+
+-- (7.3) Lists
+
+singl :: a -> [a]
+singl = return
+
+-- (7.4) Strong monads -----------------------------------------------------------
+
+class (Functor f, Monad f) => Strong f where
+      rstr :: (f a >< b) -> f (a >< b)
+      rstr (x, b) = do a <- x ; return (a, b)
+
+      lstr :: (b >< f a) -> f (b >< a)
+      lstr(b, x) = do a <- x ; return (b, a)
+
+instance Strong IO
+
+instance Strong []
+
+instance Strong Maybe
+
+dstr :: Strong m => (m a, m b) -> m (a, b)       --- double strength
+--dstr = mult . fmap rstr . lstr
+dstr = rstr .! lstr
+
+splitm :: Strong ff => ff (a -> b) -> a -> ff b
+-- Exercise 4.8.13 in Jacobs' "Introduction to Coalgebra" (2012)
+splitm = curry (fmap ap . rstr)
+
+{--
+-- (7.5) Monad transformers ------------------------------------------------------
+
+class (Monad m, Monad (t m))  => MT t m where   -- monad transformer class
+      lift :: m a -> t m a
+
+-- nested lifting:
+
+dlift :: (MT t (t1 m), MT t1 m) => m a -> t (t1 m) a
+dlift = lift . lift
+
+--}
+
+-- (8) Basic functions, abbreviations ------------------------------------------
+
+bang :: a -> ()
+bang = (!)
+
+dup :: c -> c >< c
+dup = split id id
+
+zero :: b -> Integer
+zero = const 0
+
+one :: b -> Integer
+one  = const 1
+
+nil :: b -> [a]
+nil = const []
+
+cons :: (a >< [a]) -> [a]
+cons = uncurry (:)
+
+add :: (Integer >< Integer) -> Integer
+add = uncurry (+)
+
+mul :: (Integer, Integer) -> Integer
+mul = uncurry (*)
+
+conc :: ([a] >< [a]) -> [a]
+conc = uncurry (++)
+
+true :: b -> Bool
+true = const True
+
+nothing :: b -> Maybe a
+nothing = const Nothing
+
+false :: b -> Bool
+false = const False
+
+inMaybe :: () -|- a -> Maybe a
+inMaybe = either (const Nothing) Just
+
+-- (9) Advanced ----------------------------------------------------------------
+
+class (Functor f) => Unzipable f where
+      unzp :: f (a >< b) -> (f a >< f b)
+      unzp = split (fmap p1) (fmap p2)
+
+class Functor g => DistL g where
+      lamb :: Monad m => g (m a) -> m (g a)
+
+instance DistL [] where lamb = sequence
+
+instance DistL Maybe where
+      lamb Nothing  = return Nothing
+      lamb (Just a) = fmap Just a  -- where mp f = (return.f).!id
+
+aap :: Monad m  => m (a->b) -> m a -> m b
+-- to convert Monad into Applicative
+-- (<*>) = curry(lift ap) where lift h (x,y) = do { a <- x; b <- y; return ((curry h a b)) }
+aap mf mx = do f <- mf ; f <$> mx
+
+-- gather: n-ary split
+
+gather :: [a -> b] -> a -> [b]
+gather l x = map ($ x) l
+
+-- the dual of zip
+
+cozip :: (Functor f) => f a -|- f b -> f (a -|- b)
+cozip = either (fmap Left) (fmap Right)
+
+--------------------------------------------------------------------------------
+tot :: (a -> b) -> (a -> Bool) -> a -> Maybe b
+tot f p = cond p (return . f) nothing
+--------------------------------------------------------------------------------
diff --git a/examples/Main.hs b/examples/Main.hs
new file mode 100644
--- /dev/null
+++ b/examples/Main.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE KindSignatures, TypeFamilies, DeriveFunctor, DeriveTraversable,
+    DeriveFoldable #-}
+
+module Main where
+
+import Data.Combinators.TH
+import Cp -- Program Calculus Combinators library
+import Data.Functor.Foldable -- Recursion schemes library
+import Data.Functor.Foldable.TH -- Recursion schemes makeBaseFunctor
+import Data.List (foldl')
+
+makeCombinator ''ListF
+
+l :: [a] -> Integer
+l = cata (listf zero (succ . p2))
+
+data BTree a = Empty | Node(a, (BTree a, BTree a)) deriving Show
+
+makeBaseFunctor ''BTree
+makeCombinator ''BTree
+makeCombinator ''BTreeF
+
+countBTree :: BTree a -> Integer
+countBTree = cata (btreef (const 0) (succ . uncurry (+) . p2))
+
+data Expr a
+    = Lit a
+    | Add (Expr a) (Expr a)
+    | Expr a :* [Expr a]
+    deriving (Show)
+
+makeBaseFunctor ''Expr
+makeCombinator ''Expr
+makeCombinator ''ExprF
+
+eval :: Expr Integer -> Integer
+eval = cata (exprf id add (uncurry $ foldl' (*)))
+
+expr1 :: Expr Integer
+expr1 = Add (Lit 2) (Mul (Lit 3) [Lit 4])
+
+data A a = C { v :: a, w :: a } | D { x :: a, z :: a }
+
+makeCombinator ''A
+
+data ExprInfix a
+    = ExprInfix a :** [ExprInfix a]
+    | AddI (ExprInfix a) (ExprInfix a)
+    | LitI a
+  deriving (Show)
+
+makeCombinator ''ExprInfix
+
+{- GADTs are not currently supported!
+data B = forall a. Eq a => B [a]
+
+makeCombinator ''B
+-}
+
+main :: IO ()
+main = undefined
+
diff --git a/src/Data/Combinators/TH.hs b/src/Data/Combinators/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Combinators/TH.hs
@@ -0,0 +1,83 @@
+module Data.Combinators.TH (makeCombinator) where
+
+import Language.Haskell.TH
+import Control.Monad
+import Data.Char
+
+-- (1) Main generation function -----
+
+{- | Build a special combinator given a data type name.
+e.g.
+
+@
+
+-- List type
+data List a = Nil | List a (List a)
+
+makeCombinator ''List
+@
+
+This example will generate the following code:
+
+@ 
+makeCombinator ''ListF
+ ======>
+  listf f_acw7 f_acw8 Nil = f_acw7 ()
+  listf f_acw7 f_acw8 (Cons a_acw9 a_acwa) = f_acw8 (a_acw9, a_acwa)
+@
+-}
+makeCombinator :: Name -> Q [Dec]
+makeCombinator t = do
+    TyConI (DataD _ _ _ _ constructors _) <- reify t
+
+    pe <- genPE "f" (length constructors)
+
+    let combName = mkName . map toLower . nameBase $ t
+        clauses  = map (combinClause pe) $ zip constructors [0..]
+    r <- funD combName clauses
+    return [r]
+
+-----
+
+-- (2) makeCombinator auxiliary function -----
+-- Generates a single function clause
+
+combinClause :: ([PatQ], [ExpQ]) -- Function arguments pattern
+             -> (Con, Int) -- (Constructor, Indice of current constructor)
+             -> ClauseQ
+combinClause (patsF, varsF) (NormalC name fields, i) = do (patsC, varsC) <- genPE "a" (length fields)
+                                                          funClause patsF varsF patsC varsC name (length fields) i
+combinClause (patsF, varsF) (RecC name fields, i)    = do (patsC, varsC) <- genPE "a" (length fields)
+                                                          funClause patsF varsF patsC varsC name (length fields) i
+combinClause (patsF, varsF) (InfixC _ name _, i)     = do (patsC, varsC) <- genPE "a" 2
+                                                          funClause patsF varsF patsC varsC name 2 i
+combinClause _ (ForallC{}, _)  = error "makeCombinator: GADTs are not currently supported."
+combinClause _ (GadtC{}, _)    = error "makeCombinator: GADTs are not currently supported."
+combinClause _ (RecGadtC{}, _) = error "makeCombinator: GADTs are not currently supported."
+
+-----
+
+-- (3) combinClause auxiliary functions -----
+funClause :: [PatQ] -> [ExpQ] -> [PatQ] -> [ExpQ] -> Name -> Int -> Int -> ClauseQ
+funClause pF vF pC vC name l i = 
+    clause (pF ++ [conP name pC]) 
+           (normalB (appE (vF !! i) 
+                          (applyConVars vC name vC (l - 1)))) 
+           []
+
+applyConVars :: [ExpQ] -> t -> [a] -> Int -> ExpQ
+applyConVars _ _ [] _             = conE (mkName "()")
+applyConVars varsC _ [_] n        = varsC !! n
+applyConVars varsC name' (_:fs) n = tupE (applyConVars varsC name' fs (n-1) : [varsC !! n])
+
+------
+
+-- (4) General auxiliary functions -----
+
+-- Generate n unique variables and return them in form of patterns and expressions
+genPE :: String -> Int -> Q ([PatQ], [ExpQ])
+genPE x n = do
+  ids <- replicateM n (newName x)
+  return (map varP ids, map varE ids)
+
+-----
