diff --git a/atomic-modify.cabal b/atomic-modify.cabal
new file mode 100644
--- /dev/null
+++ b/atomic-modify.cabal
@@ -0,0 +1,31 @@
+-- This file has been generated from package.yaml by hpack version 0.17.0.
+--
+-- see: https://github.com/sol/hpack
+
+name:           atomic-modify
+version:        0.1.0.0
+synopsis:       A typeclass for mutable references that have an atomic modify operation.
+
+description:    A typeclass for mutable references that have an atomic modify operation. Generalizes atomic modify operations in IO and STM contexts for IORef, MVar, TVar, and TMVar.
+category:       Concurrency
+homepage:       https://github.com/chris-martin/haskell-libraries
+author:         Chris Martin <ch.martin@gmail.com>
+maintainer:     Chris Martin <ch.martin@gmail.com>
+license:        Apache-2.0
+license-file:   license.txt
+build-type:     Simple
+cabal-version:  >= 1.10
+
+library
+  hs-source-dirs:
+      src
+  default-extensions: NoImplicitPrelude
+  ghc-options: -Wall
+  build-depends:
+      base >= 4.9 && < 4.10
+    , stm
+  exposed-modules:
+      Control.Concurrent.AtomicModify
+  other-modules:
+      Paths_atomic_modify
+  default-language: Haskell2010
diff --git a/license.txt b/license.txt
new file mode 100644
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,13 @@
+Copyright 2017 Chris Martin
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/src/Control/Concurrent/AtomicModify.hs b/src/Control/Concurrent/AtomicModify.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Concurrent/AtomicModify.hs
@@ -0,0 +1,110 @@
+{- |
+
+Provides 'AtomicModify', a typeclass for mutable references that have an atomic
+modify operations. This generalizes atomic modify operations in 'IO' and 'STM'
+contexts for 'IORef', 'MVar', 'TVar', and 'TMVar'.
+
+* 'IORef' and 'MVar' can be modified in 'IO'.
+* 'TVar' and 'TMVar' can be modified in 'IO' or 'STM'.
+
+-}
+
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+module Control.Concurrent.AtomicModify
+    ( AtomicModify (..)
+    , atomicModifyStrict_
+    , atomicModifyLazy_
+    ) where
+
+import Control.Concurrent.MVar (MVar, modifyMVar)
+import Control.Concurrent.STM (STM, TMVar, TVar, atomically, putTMVar, readTVar,
+                               takeTMVar, writeTVar)
+import Data.IORef (IORef, atomicModifyIORef, atomicModifyIORef')
+import Prelude (IO, pure, ($), ($!))
+
+{- |
+A typeclass for mutable references that have an atomic modify operation.
+
+Type variables:
+
+* @ref@ - The reference (e.g. 'IORef', 'TVar', 'MVar', 'TMVar')
+* @m@ - The monad in which the modification takes place (e.g. 'IO', 'STM')
+
+As the name "atomic" implies, these functions are useful for using mutable
+references in a safe way to prevent race conditions in a multithreaded
+program.
+-}
+class AtomicModify ref m where
+
+    -- | Atomically modify the contents of a @ref@ (type @a@) and produce a
+    -- value (type @b@). This is strict; it forces the value stored in the @ref@
+    -- as well as the value returned.
+    atomicModifyStrict :: ref a -> (a -> (a, b)) -> m b
+
+    -- | Atomically modify the contents of a @ref@ (type @a@) and produce a
+    -- value (type @b@). This is lazy, which means if the program calls
+    -- 'atomicModifyLazy' many times, but seldomly uses the value, thunks will
+    -- pile up in memory resulting in a space leak.
+    atomicModifyLazy :: ref a -> (a -> (a, b)) -> m b
+
+-- | Atomically modify the contents of a @ref@. This is strict; it forces the
+-- value stored in the @ref@ as well as the value returned.
+atomicModifyStrict_ :: AtomicModify v m => v a -> (a -> a) -> m ()
+atomicModifyStrict_ ref f = atomicModifyStrict ref (\a -> (f a, ()))
+
+-- | Atomically modify the contents of a @ref@ (type @a@) and produce a value
+-- (type @b@). This is lazy, which means if the program calls
+-- 'atomicModifyLazy_' many times, but seldomly uses the value, thunks will pile
+-- up in memory resulting in a space leak.
+atomicModifyLazy_ :: AtomicModify v m => v a -> (a -> a) -> m ()
+atomicModifyLazy_ ref f = atomicModifyLazy ref (\a -> (f a, ()))
+
+
+--------------------------------------------------------------------------------
+--  Instances
+--------------------------------------------------------------------------------
+
+instance AtomicModify IORef IO where
+    atomicModifyLazy   ref f = atomicModifyIORef  ref f
+    atomicModifyStrict ref f = atomicModifyIORef' ref f
+
+instance AtomicModify MVar IO where
+    atomicModifyLazy   ref f = modifyMVar ref (\x -> pure $  f x)
+    atomicModifyStrict ref f = modifyMVar ref (\x -> pure $! f x)
+
+instance AtomicModify TVar STM where
+
+    atomicModifyLazy ref f = do
+        a <- readTVar ref
+        let (a', b) = f a
+        writeTVar ref a'
+        pure b
+
+    atomicModifyStrict ref f = do
+        a <- readTVar ref
+        let (a', b) = f a
+        writeTVar ref $! a'
+        pure $! b
+
+instance AtomicModify TMVar STM where
+
+    atomicModifyLazy ref f = do
+        a <- takeTMVar ref
+        let (a', b) = f a
+        putTMVar ref a'
+        pure b
+
+    atomicModifyStrict ref f = do
+        a <- takeTMVar ref
+        let (a', b) = f a
+        putTMVar ref $! a'
+        pure $! b
+
+instance AtomicModify TVar IO where
+    atomicModifyLazy   ref f = atomically (atomicModifyLazy   ref f)
+    atomicModifyStrict ref f = atomically (atomicModifyStrict ref f)
+
+instance AtomicModify TMVar IO where
+    atomicModifyLazy   ref f = atomically (atomicModifyLazy   ref f)
+    atomicModifyStrict ref f = atomically (atomicModifyStrict ref f)
