diff --git a/Data/HoleyMonoid.hs b/Data/HoleyMonoid.hs
new file mode 100644
--- /dev/null
+++ b/Data/HoleyMonoid.hs
@@ -0,0 +1,59 @@
+-- | Monoids with holes. The 'HoleyMonoid' allows building monoidal values of which certain components are to be filled in later. For example:
+--
+-- > > let holey = now "x = "
+-- >             . later show
+-- >             . now ", y = "
+-- >             . later show
+-- > > run holey 3 5
+-- > "x = 3, y = 5"
+--
+-- This module is intended to be imported in qualified fashion, e.g.
+--
+-- > import qualified Data.HoleyMonoid as HM
+
+module Data.HoleyMonoid (
+  HoleyMonoid, run,
+  now, later, map
+  
+  ) where
+
+import Prelude hiding (id, (.), map)
+import Control.Category
+import Data.Monoid
+
+-- | The type of a monoid with holes. The underlying monoid is represented by
+-- type parameter @m@. The @r@ is the result type and stays polymorphic until the
+-- very last moment when 'run' is called. The last argument @a@ is always a
+-- function with zero or more arguments, finally resulting in @r@. Ordering the
+-- arguments in this order allows holey monoids to be composed using `.`, stacking the
+-- expected arguments. Note that the `Monoid` constraint is only used in the
+-- identity 'HoleyMonoid' and in composing two 'HoleyMonoid's.
+newtype HoleyMonoid m r a = HoleyMonoid { runHM :: (m -> r) -> a }
+
+instance Monoid m => Category (HoleyMonoid m) where
+  id    = now mempty
+  f . g = f `bind` \a -> g `bind` \b -> now (a `mappend` b)
+
+-- | Insert a constant monoidal value.
+now :: m -> HoleyMonoid m r r
+now a = HoleyMonoid ($ a)
+
+-- | Monadic indexed bind for holey monoids.
+bind :: HoleyMonoid m b c -> (m -> HoleyMonoid n a b) -> HoleyMonoid n a c
+m `bind` f = HoleyMonoid $ \k -> runHM m (\a -> runHM (f a) k)
+
+-- | Insert a monoidal value that is not specified until the computation is
+-- 'run'. The argument that is expected later is converted to the monoid type
+-- using the given conversion function.
+later :: (a -> m) -> HoleyMonoid m r (a -> r)
+later f = HoleyMonoid (. f)
+
+-- | Convert between underlying 'Monoid' types.
+map :: (m -> n) -> HoleyMonoid m r a -> HoleyMonoid n r a
+map g m = HoleyMonoid (\k -> runHM m (k . g))
+
+-- | Run the computation, resulting in a function that still expects some
+-- arguments. The number of arguments that is still expected will be equal to the
+-- number of 'later's the computation is built of.
+run :: HoleyMonoid m m a -> a
+run m = runHM m id
diff --git a/HoleyMonoid.cabal b/HoleyMonoid.cabal
new file mode 100644
--- /dev/null
+++ b/HoleyMonoid.cabal
@@ -0,0 +1,27 @@
+Name:           HoleyMonoid
+Version:        0.1
+Synopsis:       Monoids with holes.
+Description:   	The 'HoleyMonoid' allows building monoidal values of which certain components are to be filled in later. For example:
+                .
+                > > let holey = now "x = "
+                >             . later show
+                >             . now ", y = "
+                >             . later show
+                > > run holey 3 5
+                > "x = 3, y = 5"
+
+Author:         Martijn van Steenbergen
+Maintainer:     Martijn van Steenbergen <martijn@van.steenbergen.nl>
+Stability:      Experimental
+Copyright:      Some Rights Reserved (CC) 2009 Martijn van Steenbergen
+Homepage:       http://code.google.com/p/monoid-cont/
+
+Cabal-Version:  >= 1.2
+License:        BSD3
+License-file:   LICENSE
+Category:       Data Structures
+Build-type:     Simple
+
+Library
+  Exposed-Modules:  Data.HoleyMonoid
+  Build-Depends:    base >= 4, base < 5
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2009, Martijn van Steenbergen
+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 the author nor the
+      names of his contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 <copyright holder> 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,2 @@
+import Distribution.Simple
+main = defaultMain
