diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2017
+
+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 Author name here 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1 @@
+# incremental
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/incremental.cabal b/incremental.cabal
new file mode 100644
--- /dev/null
+++ b/incremental.cabal
@@ -0,0 +1,34 @@
+name:                incremental
+version:             0
+synopsis:            incremental update library
+description:         Generic interface for incremental updates
+homepage:            https://github.com/fumieval/incremental#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Fumiaki Kinoshita
+maintainer:          fumiexcel@gmail.com
+copyright:           2017 Fumiaki Kinoshita
+category:            Data
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Data.Incremental
+  build-depends:       base >= 4.8 && <5, containers, semigroups, deepseq
+  ghc-options: -Wall
+  default-language:    Haskell2010
+
+test-suite incremental-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , incremental
+  ghc-options:         -threaded
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/fumieval/incremental
diff --git a/src/Data/Incremental.hs b/src/Data/Incremental.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Incremental.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE StandaloneDeriving #-}
+module Data.Incremental (
+  Incremental(..)
+  , Alter(..)
+  , Hetero(..)
+  , Fresh(..)
+) where
+
+import Control.Applicative
+import Control.DeepSeq
+import Data.Fixed
+import Data.Functor.Identity
+import Data.Semigroup hiding (diff)
+import qualified Data.IntMap.Strict as IntMap
+import qualified Data.Map.Strict as Map
+import Data.Proxy
+import qualified Data.Set as Set
+import Data.Void
+import Data.Int
+import Data.Word
+import Numeric.Natural
+import GHC.Generics
+
+class Incremental a where
+  -- | the difference type
+  type Delta a
+  -- | @'maybe' a ('patch' a) ('diff' b a) ≡ b@
+  patch :: a -> Delta a -> a
+  -- | returns 'Nothing' when there is no update
+  diff :: a -> a -> Maybe (Delta a)
+
+instance Incremental () where
+  type Delta () = Void
+  patch _ _ = ()
+  diff _ _ = Nothing
+
+instance Incremental Void where
+  type Delta Void = Void
+  patch v _ = v
+  diff _ _ = Nothing
+
+instance Incremental (Proxy a) where
+  type Delta (Proxy a) = Void
+  patch v _ = v
+  diff _ _ = Nothing
+
+instance Incremental a => Incremental (Identity a) where
+  type Delta (Identity a) = Delta a
+  patch (Identity a) d = Identity (patch a d)
+  diff (Identity a) (Identity b) = diff a b
+
+instance Incremental a => Incremental (Const a b) where
+  type Delta (Const a b) = Delta a
+  patch (Const a) d = Const (patch a d)
+  diff (Const a) (Const b) = diff a b
+
+data Alter a = Insert a | Update (Delta a) | Delete | Upsert a (Delta a)
+  deriving Generic
+
+deriving instance (Show a, Show (Delta a)) => Show (Alter a)
+instance (NFData a, NFData (Delta a)) => NFData (Alter a)
+
+instance (Incremental a, Semigroup (Delta a)) => Semigroup (Alter a) where
+  _ <> Insert a = Insert a
+  _ <> Delete = Delete
+  Insert a <> Update d = Insert (patch a d)
+  Insert a <> Upsert _ d = Insert (patch a d)
+  Update c <> Update d = Update (c <> d)
+  Update c <> Upsert a d = Upsert a (c <> d)
+  Delete <> Update _ = Delete
+  Delete <> Upsert a _ = Insert a
+  Upsert a d <> Update e = Upsert a (d <> e)
+  Upsert a d <> Upsert _ e = Upsert a (d <> e)
+
+instance (Incremental a, Semigroup (Delta a), Monoid (Delta a)) => Monoid (Alter a) where
+  mempty = Update mempty
+  mappend = (<>)
+
+instance Incremental a => Incremental (Maybe a) where
+  type Delta (Maybe a) = Alter a
+  patch _ (Insert a) = Just a
+  patch (Just a) (Update d) = Just $! patch a d
+  patch (Just a) (Upsert _ d) = Just $! patch a d
+  patch _ (Upsert a _) = Just a
+  patch _ _ = Nothing
+  diff Nothing (Just a) = Just $ Insert a
+  diff (Just a) (Just b) = Update <$> diff a b
+  diff (Just _) Nothing = Just Delete
+  diff _ _ = Nothing
+
+instance (Incremental a, Incremental b) => Incremental (a, b) where
+  type Delta (a, b) = (Maybe (Delta a), Maybe (Delta b))
+  patch (a, b) (d, e) = (maybe a (patch a) d, maybe b (patch b) e)
+  diff (a, b) (c, d) = Just (diff a c, diff b d)
+
+instance (Incremental a, Incremental b, Incremental c) => Incremental (a, b, c) where
+  type Delta (a, b, c) = (Maybe (Delta a), Maybe (Delta b), Maybe (Delta c))
+  patch (a, b, c) (d, e, f) = (maybe a (patch a) d, maybe b (patch b) e, maybe c (patch c) f)
+  diff (a, b, c) (d, e, f) = Just (diff a d, diff b e, diff c f)
+
+instance (Incremental a) => Incremental (IntMap.IntMap a) where
+  type Delta (IntMap.IntMap a) = IntMap.IntMap (Alter a)
+  patch = IntMap.mergeWithKey (\_ a -> patch (Just a)) id
+    $ IntMap.mapMaybe $ \case
+      Insert a -> Just a
+      Upsert a _ -> Just a
+      _ -> Nothing
+  diff = (check.). IntMap.mergeWithKey (\_ a b -> Update <$> diff a b) (IntMap.map (const Delete)) (IntMap.map Insert)
+    where
+      check m = if IntMap.null m then Nothing else Just m
+
+instance (Ord k, Incremental a) => Incremental (Map.Map k a) where
+  type Delta (Map.Map k a) = Map.Map k (Alter a)
+  patch = Map.mergeWithKey (\_ a -> patch (Just a)) id
+    $ Map.mapMaybe $ \case
+      Insert a -> Just a
+      Upsert a _ -> Just a
+      _ -> Nothing
+  diff = (check.). Map.mergeWithKey (\_ a b -> Update <$> diff a b) (Map.map (const Delete)) (Map.map Insert)
+    where
+      check m = if Map.null m then Nothing else Just m
+
+instance Ord a => Incremental (Set.Set a) where
+  -- | (insertion, deletion)
+  type Delta (Set.Set a) = (Set.Set a, Set.Set a)
+  patch s (ins, del) = s `Set.difference` del `Set.union` ins
+  diff a b = check $ go (Set.toAscList a) (Set.toAscList b) Set.empty Set.empty where
+    go xs'@(x:xs) ys'@(y:ys) s t = case compare x y of
+      LT -> go xs ys' s (Set.insert x t)
+      EQ -> go xs ys s t
+      GT -> go xs' ys (Set.insert y s) t
+    go xs ys s t = (foldr Set.insert s ys, foldr Set.insert t xs)
+    check r@(s, t)
+      | Set.null s, Set.null t = Nothing
+      | otherwise = Just r
+
+instance Num a => Incremental (Sum a) where
+  type Delta (Sum a) = Sum a
+  patch = (<>)
+  diff (Sum a) (Sum b) = Just $ Sum (b - a)
+
+newtype Hetero a = Hetero { getHetero :: a }
+  deriving (Bounded, Enum, Eq, Floating, Fractional, Integral, Semigroup
+      , Monoid, Num, Ord, Real, RealFrac, RealFloat, Generic, NFData)
+
+-- | 'diff' checks equality
+instance Eq a => Incremental (Hetero a) where
+  type Delta (Hetero a) = a
+  patch _ = Hetero
+  diff (Hetero a) (Hetero b)
+    | a /= b = Just b
+    | otherwise = Nothing
+
+newtype Fresh a = Fresh { getFresh :: a }
+  deriving (Bounded, Enum, Eq, Floating, Fractional, Integral, Semigroup
+      , Monoid, Num, Ord, Real, RealFrac, RealFloat, Generic, NFData)
+
+-- | Always updated
+instance Incremental (Fresh a) where
+  type Delta (Fresh a) = a
+  patch _ = Fresh
+  diff _ = Just . getFresh
+
+#define TRIVIAL_EQ(ty) instance Incremental (ty) where { \
+  type Delta (ty) = ty; \
+  patch _ x = x; \
+  diff a b = if a /= b then Just b else Nothing; \
+  }
+
+TRIVIAL_EQ(Bool)
+TRIVIAL_EQ(Char)
+TRIVIAL_EQ(Double)
+TRIVIAL_EQ(Float)
+TRIVIAL_EQ(Fixed a)
+TRIVIAL_EQ(Int)
+TRIVIAL_EQ(Int8)
+TRIVIAL_EQ(Int16)
+TRIVIAL_EQ(Int32)
+TRIVIAL_EQ(Int64)
+TRIVIAL_EQ(Integer)
+TRIVIAL_EQ(Natural)
+TRIVIAL_EQ(Ordering)
+TRIVIAL_EQ(Word)
+TRIVIAL_EQ(Word8)
+TRIVIAL_EQ(Word16)
+TRIVIAL_EQ(Word32)
+TRIVIAL_EQ(Word64)
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
