diff --git a/Data/MemoUgly.hs b/Data/MemoUgly.hs
new file mode 100644
--- /dev/null
+++ b/Data/MemoUgly.hs
@@ -0,0 +1,24 @@
+module Data.MemoUgly(memoIO, memo) where
+import Control.Concurrent.MVar
+import qualified Data.Map as M
+import System.IO.Unsafe(unsafePerformIO)
+
+-- | Memoize the given function by allocating a memo table,
+-- and then updating the memo table on each function call.
+memoIO :: (Ord a)
+       => (a -> b)           -- ^Function to memoize
+       -> IO (a -> IO b)
+memoIO f = do
+    v <- newMVar M.empty
+    let f' x = do
+            m <- readMVar v
+            case M.lookup x m of
+                Nothing -> do let { r = f x }; m <- takeMVar v; putMVar v (M.insert x r m); return r
+                Just r  -> return r
+    return f'
+
+-- | The pure version of 'memoIO'.
+memo :: (Ord a)
+     => (a -> b)           -- ^Function to memoize
+     -> (a -> b)
+memo f = let f' = unsafePerformIO (memoIO f) in \ x -> unsafePerformIO (f' x)
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/uglymemo.cabal b/uglymemo.cabal
new file mode 100644
--- /dev/null
+++ b/uglymemo.cabal
@@ -0,0 +1,15 @@
+Name:                uglymemo
+Version:             0.1.0.0
+Synopsis:            A simple (but internally ugly) memoization function.
+Description:         A simple (but internally ugly) memoization function.
+License:             PublicDomain
+Author:              Lennart Augustsson
+Maintainer:          lennart@augustsson.net
+Category:            Data
+Build-type:          Simple
+Cabal-version:       >=1.2
+
+
+Library
+  Exposed-modules:     Data.MemoUgly
+  Build-depends:       base < 10, containers
