diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2012, Dan Burton
+
+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 Dan Burton 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/io-memoize.cabal b/io-memoize.cabal
new file mode 100644
--- /dev/null
+++ b/io-memoize.cabal
@@ -0,0 +1,44 @@
+name:                io-memoize
+version:             1.0.0.0
+synopsis:            Memoize IO actions
+description:
+  Transform an IO action into a similar IO action
+  that performs the original action only once.
+  .
+  You can choose to perform the original action
+  in one of three ways:
+  .
+  (1) lazily (might never be performed)
+  .
+  (2) eagerly
+  .
+  (3) concurrently (eager)
+  .
+  Special thanks to shachaf and headprogrammingczar from #haskell irc
+  for helping me reason about the behavior of this library.
+
+
+license:             BSD3
+license-file:        LICENSE
+author:              Dan Burton
+maintainer:          danburton.email@gmail.com
+copyright:           (c) 2012 Dan Burton
+
+category:            System
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  hs-source-dirs:    src
+  exposed-modules:   System.IO.Memoize
+  build-depends:     base == 4.*, spawn
+  ghc-options:       -Wall
+
+source-repository head
+  type:     git
+  location: git://github.com/DanBurton/io-memoize
+
+source-repository this
+  type:     git
+  location: git://github.com/DanBurton/io-memoize
+  tag:      io-memoize-1.0.0.0
diff --git a/src/System/IO/Memoize.hs b/src/System/IO/Memoize.hs
new file mode 100644
--- /dev/null
+++ b/src/System/IO/Memoize.hs
@@ -0,0 +1,91 @@
+-- | Memoize IO actions,
+-- performing them at most once,
+-- but recalling their result for subsequent invocations.
+-- This library provides three sequencing strategies:
+-- lazy ('ioMemo'), eager ('ioMemo''), and concurrent ('ioMemoPar').
+-- 
+-- The lazy and eager approaches give stronger sequencing guarantees.
+-- 
+-- The following property holds: @join . ioMemo === id@.
+-- The same is true for @ioMemo'@ and @ioMemoPar@.
+-- 
+-- Also, for the three memoizers in this library,
+-- the memory allocated for the result will not
+-- be available for garbage collection until the corresponding
+-- memoized action is also available for garbage collection,
+-- unless your compiler performs deep magicks.
+module System.IO.Memoize (
+    ioMemo
+  , ioMemo'
+  , ioMemoPar
+  ) where
+
+import Control.Concurrent.Spawn
+import Control.Concurrent.MVar
+import Data.IORef
+
+-- | Memoize an IO action.
+-- The action will be performed
+-- the first time that it its value is demanded;
+-- all subsequent invocations
+-- will simply recall the value acquired
+-- from the first call.
+-- If the value is never demanded,
+-- then the action will never be performed.
+-- 
+-- This is basically a safe version of
+-- 'System.IO.Unsafe.unsafeInterleaveIO'.
+-- This function is also thread-safe:
+-- it is guaranteed that the action passed in
+-- will be performed exactly 0 or 1 times
+-- by this code. Exceptions will be propagated
+-- to the caller.
+-- 
+-- Example usage:
+-- 
+-- >>> getLine' <- ioMemo getLine
+-- 
+-- >>> replicateM 3 getLine'
+-- Hello
+-- ["Hello", "Hello", "Hello"]
+ioMemo :: IO a -> IO (IO a)
+ioMemo action = do
+  memo <- newIOMemoizer
+  return (memo action)
+
+-- | Memoize an IO action.
+-- The action will be performed immediately;
+-- all subsequent invocations
+-- will recall the value acquired.
+ioMemo' :: IO a -> IO (IO a)
+ioMemo' action = do
+  v <- action
+  return (return v)
+
+-- | Memoize an IO action.
+-- The action will be performed immediately
+-- in a spawned thread.
+-- Attempts to access the result
+-- will block until the action is finished.
+-- 
+-- This is simply a synonym for 'Control.Concurrent.Spawn.spawn'
+ioMemoPar :: IO a -> IO (IO a)
+ioMemoPar = spawn
+
+
+
+newIOMemoizer :: IO (IO a -> IO a)
+newIOMemoizer = do
+  b <- newMVar True
+  r <- newIORef undefined
+  return (ioMemoizer b r)
+
+ioMemoizer :: MVar Bool -> IORef a -> IO a -> IO a
+ioMemoizer b r action = do
+  modifyMVar_ b $ \isEmpty ->
+    if isEmpty
+      then do v <- action
+              writeIORef r v
+              return False
+      else return False
+  readIORef r
