diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2012 Tony Morris
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 AUTHORS 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,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/diet.cabal b/diet.cabal
new file mode 100644
--- /dev/null
+++ b/diet.cabal
@@ -0,0 +1,38 @@
+Name:               diet
+Version:            0.0.1
+License:            BSD3
+License-File:       LICENSE
+Author:             Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+Maintainer:         Tony Morris
+Copyright:          Tony Morris
+Synopsis:           Discrete Interval Encoding Tree
+Category:           Development
+Description:        Discrete Interval Encoding Tree described by Martin Erwig in /Diets for Fat Sets, January 1993/.
+Homepage:           https://github.com/tonymorris/diet
+Cabal-Version:      >= 1.6
+Build-Type:         Simple
+
+Source-Repository   head
+  Type:             git
+  Location:         git@github.com:tonymorris/diet.git
+
+Flag                small_base
+  Description:      Choose the new, split-up base package.
+
+Library
+  Build-Depends:
+                    base < 5 && >= 3
+
+  GHC-Options:
+                    -Wall
+
+  Hs-Source-Dirs:
+                    src
+
+  Exposed-Modules:
+                    Data.Set.Diet
+
+  GHC-Options:      
+                   -Wall
+                   -funbox-strict-fields
+
diff --git a/src/Data/Set/Diet.hs b/src/Data/Set/Diet.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Set/Diet.hs
@@ -0,0 +1,299 @@
+-- | Discrete Interval Encoding Tree described by Martin Erwig in /Diets for Fat Sets, January 1993/.
+module Data.Set.Diet(
+  Interval
+, point
+, interval
+, intervalMin
+, intervalMax
+, mergeI
+, isPointed
+, mapI
+, Diet
+, member
+, notMember
+, insert
+, delete
+, empty
+, single
+, singleI
+, size
+, diet
+, toList
+, fromList
+, mapD
+) where
+
+import Data.Ix
+import Data.Foldable(foldl', Foldable)
+
+-- | An interval with discrete values between.
+data Interval a =
+  Interval a a
+  deriving (Eq, Ord)
+
+instance (Eq a, Show a) => Show (Interval a) where
+  show (Interval a1 a2) =
+    '[' : show a1 ++ (if a1 == a2 then [] else '|' : show a2) ++ "]"
+
+-- | An interval with the same minimum and maximum.
+point ::
+  a
+  -> Interval a
+point a =
+  Interval a a
+
+-- | Construct an interval ensuring that the minimum is less than or equal to maximum.
+interval ::
+  Ord a =>
+  a
+  -> a
+  -> Interval a
+interval a1 a2 =
+  if a1 <= a2
+    then
+      Interval a1 a2
+    else
+      Interval a2 a1
+
+-- | The minimum of the interval.
+intervalMin ::
+  Interval a
+  -> a
+intervalMin (Interval a _) =
+  a
+
+-- | The maximum of the interval.
+intervalMax ::
+  Interval a
+  -> a
+intervalMax (Interval _ a) =
+  a
+
+-- | Merge two intervals if they are overlapping or adjacent.
+mergeI ::
+  (Ord a, Enum a) =>
+  Interval a
+  -> Interval a
+  -> Maybe (Interval a)
+mergeI (Interval a1 a2) (Interval aa1 aa2) =
+  if (a1 <= aa2 && succ a2 >= aa1) || (aa1 <= a2 && succ aa2 >= a1)
+    then
+      Just $ Interval (min a1 aa1) (max a2 aa2)
+    else
+      Nothing
+
+-- | Returns whether or not the interval has the same minimum and maximum.
+isPointed ::
+  Eq a =>
+  Interval a
+  -> Bool
+isPointed (Interval a1 a2) =
+  a1 == a2
+
+-- | Map a function across the minimum and maximum of the interval.
+mapI ::
+  Ord b =>
+  (a -> b)
+  -> Interval a
+  -> Interval b
+mapI f (Interval a1 a2) =
+  interval (f a1) (f a2)
+
+-- | A Discrete Interval Encoding Tree.
+data Diet a =
+  Empty
+  | Node (Diet a) (Interval a) (Diet a)
+  deriving (Eq, Ord)
+
+instance (Eq a, Show a) => Show (Diet a) where
+  showsPrec _ Empty =
+    id
+  showsPrec n (Node l i r) =
+    showsPrec n l . shows i . showsPrec n r
+
+-- | Test for membership in the interval tree.
+member ::
+  Ix a =>
+  a
+  -> Diet a
+  -> Bool
+member _ Empty =
+  False
+member x (Node l (Interval a1 a2) r) =
+  inRange (a1, a2) x || member x (if x < a1 then l else r)
+
+-- | Test for non-membership in the interval tree.
+notMember ::
+  Ix a =>
+  a
+  -> Diet a
+  -> Bool
+notMember a =
+  not . member a
+
+-- | Insert an element into the interval tree.
+insert ::
+  (Ord a, Enum a) =>
+  a
+  -> Diet a
+  -> Diet a
+insert x Empty =
+  Node Empty (point x) Empty
+insert x d@(Node l i@(Interval a1 a2) r)
+  | x < a1 =
+    if succ x == a1
+      then
+        let joinLeft md@(Node Empty _ _) =
+              md
+            joinLeft (Node ml mi@(Interval ma1 ma2) mr) =
+              let (ml', Interval ml1 ml2) = splitMax ml
+              in if succ ml2 == ma1
+                   then
+                     Node ml' (Interval ml1 ma2) mr
+                   else
+                     Node ml mi mr
+            joinLeft Empty =
+              error "Broken invariant @ Data.Set.Diet#joinLeft"
+        in joinLeft (Node l (Interval x a2) r)
+      else
+        Node (insert x l) i r
+  | x > a2 =
+    if succ a2 == x
+      then
+        let splitMin (Node Empty mi mr) =
+              (mr, mi)
+            splitMin (Node ml mi mr) =
+              let (md, mi') = splitMin ml
+              in (Node md mi mr, mi')
+            splitMin Empty =
+              error "Broken invariant @ Data.Set.Diet#splitMin"
+            joinRight jd@(Node _ _ Empty) =
+              jd
+            joinRight (Node jl ji@(Interval ja1 ja2) jr) =
+              let (jr', Interval jr1 jr2) = splitMin jr
+              in if succ ja2 == jr1
+                   then
+                     Node jl (Interval ja1 jr2) jr'
+                   else
+                     Node jl ji jr
+            joinRight Empty =
+              error "Broken invariant @ Data.Set.Diet#joinRight"
+        in joinRight (Node l (Interval a1 x) r)
+      else
+        Node l i (insert x r)
+  | otherwise =
+    d
+
+-- | Delete an element from the interval tree.
+delete ::
+  (Ord a, Enum a) =>
+  a
+  -> Diet a
+  -> Diet a
+delete _ Empty =
+  Empty
+delete x (Node l i@(Interval a1 a2) r)
+  | x < a1 =
+    Node (delete x l) i r
+  | x > a2 =
+    Node l i (delete x r)
+  | x == a1 =
+    let merge ml Empty =
+          ml
+        merge Empty mr =
+          mr
+        merge ml mr =
+          let (ml', mi) = splitMax ml
+          in Node ml' mi mr
+    in if isPointed i
+         then
+           merge l r
+         else
+           Node l (Interval (succ a1) a2) r
+  | x == a2 =
+    Node l (Interval a1 (pred a2)) r
+  | otherwise =
+    Node l (Interval a1 (pred x)) (Node Empty (Interval (succ x) a2) r)
+
+-- | Construct an interval tree with no elements.
+empty ::
+  Diet a
+empty =
+  Empty
+
+-- | Construct an interval tree with a single element.
+single ::
+  a
+  -> Diet a
+single a =
+  Node Empty (point a) Empty
+
+-- | Construct an interval tree with a single interval.
+singleI ::
+  Interval a
+  -> Diet a
+singleI a =
+  Node Empty a Empty
+
+-- | Return the number of elements in the interval tree.
+size ::
+  Ix a =>
+  Diet a
+  -> Int
+size Empty =
+  0
+size (Node l (Interval a1 a2) r) =
+  sum [size l, rangeSize (a1, a2), size r]
+
+-- | Fold on the interval tree.
+diet ::
+  (b -> Interval a -> b -> b)
+  -> b
+  -> Diet a
+  -> b
+diet _ z Empty =
+  z
+diet f z (Node l i r) =
+  f (diet f z l) i (diet f z r)
+
+-- | Return all elements of the interval tree as a list.
+toList ::
+  Ix a =>
+  Diet a
+  -> [a]
+toList =
+  diet (\l (Interval a1 a2) r -> concat [l, range (a1, a2), r]) []
+
+-- | Construct an interval tree with the elements of the list.
+fromList ::
+  (Foldable t, Ord a, Enum a) =>
+  t a
+  -> Diet a
+fromList =
+  foldl' (flip insert) Empty
+
+-- | Map a function across the interval tree.
+mapD ::
+  Ord b =>
+  (a -> b)
+  -> Diet a
+  -> Diet b
+mapD _ Empty =
+  Empty
+mapD f (Node l i r) =
+  Node (mapD f l) (mapI f i) (mapD f r)
+
+-- BEGIN not exported
+
+splitMax ::
+  Diet a
+  -> (Diet a, Interval a)
+splitMax (Node l i Empty) =
+  (l, i)
+splitMax (Node l i r) =
+  let (d, i') = splitMax r
+  in (Node l i d, i')
+splitMax Empty =
+  error "Broken invariant @ Data.Set.Diet#splitMax"
+
+-- END not exported
