diff --git a/Data/EnumFun/Lazy.hs b/Data/EnumFun/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumFun/Lazy.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE CPP #-}
+#define LAZY Lazy
+#define STRICT Strict
+#include "enumfun.inc"
diff --git a/Data/EnumFun/Lazy/Base.hs b/Data/EnumFun/Lazy/Base.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumFun/Lazy/Base.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE CPP #-}
+#define LAZY Lazy
+#define BANG
+#include "base.inc"
diff --git a/Data/EnumFun/Strict.hs b/Data/EnumFun/Strict.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumFun/Strict.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE CPP #-}
+#define LAZY Strict
+#define STRICT Lazy
+#include "enumfun.inc"
diff --git a/Data/EnumFun/Strict/Base.hs b/Data/EnumFun/Strict/Base.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumFun/Strict/Base.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE CPP #-}
+#define LAZY Strict
+#define BANG !
+#include "base.inc"
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2012, Liyang HU
+
+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 Liyang HU 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/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/enumfun.cabal b/enumfun.cabal
new file mode 100644
--- /dev/null
+++ b/enumfun.cabal
@@ -0,0 +1,41 @@
+name:           enumfun
+version:        0.5.1.0
+synopsis:       Finitely represented /total/ EnumMaps
+description:
+    Finitely represented /total/ EnumMaps. Comprises a partial EnumMap and
+    a default value. Has Applicative and Monad instances, unlike EnumMap.
+    .
+    Inspired by Conal's Data.TotalMap:
+    <http://hackage.haskell.org/package/total-map>
+homepage:       https://github.com/liyang/enumfun
+license:        BSD3
+license-file:   LICENSE
+author:         Liyang HU
+maintainer:     enumfun@liyang.hu
+copyright:      © 2012 Liyang HU
+category:       Data
+build-type:     Simple
+cabal-version:  >= 1.8
+extra-source-files:
+    include/base.inc
+    include/enumfun.inc
+
+source-repository head
+    type:       git
+    location:   http://github.com/liyang/enumfun
+
+library
+    exposed-modules:
+        Data.EnumFun.Lazy
+        Data.EnumFun.Strict
+    other-modules:
+        Data.EnumFun.Lazy.Base
+        Data.EnumFun.Strict.Base
+    build-depends:
+        base >= 4.6 && < 5,
+        enummapset-th >= 0.5.1.0 && < 0.6
+    include-dirs: include
+    ghc-options: -Wall
+
+-- vim: et sw=4 ts=4 sts=4:
+
diff --git a/include/base.inc b/include/base.inc
new file mode 100644
--- /dev/null
+++ b/include/base.inc
@@ -0,0 +1,22 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFoldable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# OPTIONS_HADDOCK not-home #-}
+
+module Data.EnumFun.LAZY.Base
+    ( EnumFun (..)
+    ) where
+
+import Data.EnumMap.LAZY (EnumMap)
+import Data.Foldable
+import Data.Traversable
+import Data.Typeable
+
+-- | Total EnumMap.
+data EnumFun k v = EnumFun BANG/**/v BANG(EnumMap k v)
+    -- ^ Default value and a finite map.
+    deriving (Eq, Functor, Foldable, Ord, Show, Traversable, Typeable)
+
+-- vim: ft=haskell:
+
diff --git a/include/enumfun.inc b/include/enumfun.inc
new file mode 100644
--- /dev/null
+++ b/include/enumfun.inc
@@ -0,0 +1,62 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+{-|
+Finitely represented /total/ EnumMaps. Comprises a partial EnumMap and
+a default value. Has Applicative and Monad instances, unlike EnumMap.
+
+Inspired by Conal's Data.TotalMap:
+<http://hackage.haskell.org/package/total-map>
+-}
+
+module Data.EnumFun.LAZY
+    ( EnumFun (..)
+    , (!)
+    , trim
+    , fromList
+    , from/**/STRICT
+    ) where
+
+import Prelude hiding (lookup)
+import Control.Applicative
+import qualified Data.EnumMap.LAZY as EnumMap
+import Data.EnumFun.LAZY.Base
+import qualified Data.EnumFun.STRICT.Base as STRICT
+import Data.Monoid
+
+instance (Enum k) => Applicative (EnumFun k) where
+    pure v = EnumFun v mempty
+    EnumFun df mf <*> EnumFun dv mv = EnumFun (df dv) $
+        EnumMap.mergeWithKey (\ _ f v -> Just (f v))
+            (fmap ($ dv)) (fmap df) mf mv
+
+instance (Enum k, Monoid v) => Monoid (EnumFun k v) where
+    mempty = pure mempty
+    mappend = liftA2 mappend
+
+instance (Enum k) => Monad (EnumFun k) where
+    return = pure
+    m >>= f = mu (f <$> m) where
+        mu :: (Enum k) => EnumFun k (EnumFun k v) -> EnumFun k v
+        mu (EnumFun (EnumFun dd dm) mf) = EnumFun dd $
+            EnumMap.mapWithKey (flip (!)) mf `EnumMap.union` dm
+
+-- | Sample a total map. Semantic function.
+(!) :: (Enum k) => EnumFun k v -> k -> v
+EnumFun d m ! k = EnumMap.findWithDefault d k m
+
+-- | Optimise an 'EnumFun', weeding out any explicit default values.
+-- A semantic no-op, i.e., @(!) . trim == (!)@.
+trim :: (Eq v) => EnumFun k v -> EnumFun k v
+trim (EnumFun d m) = EnumFun d $ EnumMap.filter (d /=) m
+
+-- | Create an 'EnumFun' from a default value and a list of key/value pairs.
+fromList :: (Enum k) => v -> [(k, v)] -> EnumFun k v
+fromList d = EnumFun d . EnumMap.fromList
+
+-- | Convert from a STRICT EnumFun. The operation is essentially free; we
+-- only needed two distinct types for the different class instances.
+from/**/STRICT :: STRICT.EnumFun k v -> EnumFun k v
+from/**/STRICT (STRICT.EnumFun d m) = EnumFun d m
+
+-- vim: ft=haskell:
+
