diff --git a/Data/DAWG.hs b/Data/DAWG.hs
new file mode 100644
--- /dev/null
+++ b/Data/DAWG.hs
@@ -0,0 +1,104 @@
+-- | The module provides implementation of /directed acyclic word graphs/
+-- (DAWGs) also known as /minimal acyclic finite-state automata/.
+-- The implementation provides fast insert and (TODO:)delete operations
+-- which can be used to build the DAWG structure incrementaly.
+
+module Data.DAWG
+( DAWG (..)
+, empty
+, size
+, insert
+, lookup
+, fromList
+, fromLang
+) where
+
+import Prelude hiding (lookup)
+import Control.Applicative ((<$>), (<*>))
+import Data.List (foldl')
+import Data.Binary (Binary, put, get)
+import qualified Control.Monad.State.Strict as S
+
+import Data.DAWG.Graph (Id, Node, Graph)
+import qualified Data.DAWG.Graph as G
+
+type GraphM a b = S.State (Graph a) b
+
+mkState :: (Graph a -> Graph a) -> Graph a -> ((), Graph a)
+mkState f g = ((), f g)
+
+-- | Return node with the given identifier.
+nodeBy :: Id -> GraphM a (Node a)
+nodeBy i = G.nodeBy i <$> S.get
+
+-- Evaluate the 'G.insert' function within the monad.
+insertNode :: Ord a => Node a -> GraphM a Id
+insertNode = S.state . G.insert
+
+-- Evaluate the 'G.delete' function within the monad.
+deleteNode :: Ord a => Node a -> GraphM a ()
+deleteNode = S.state . mkState . G.delete
+
+insertM :: Ord a => String -> a -> Id -> GraphM a Id
+insertM [] y i = do
+    n <- nodeBy i
+    deleteNode n
+    insertNode (n { G.value = Just y })
+insertM (x:xs) y i = do
+    n <- nodeBy i
+    j <- case G.onChar x n of
+        Just j  -> return j
+        Nothing -> insertNode G.leaf
+    k <- insertM xs y j
+    deleteNode n
+    insertNode (G.subst x k n)
+    
+lookupM :: String -> Id -> GraphM a (Maybe a)
+lookupM [] i = G.value <$> nodeBy i
+lookupM (x:xs) i = do
+    n <- nodeBy i
+    case G.onChar x n of
+        Just j  -> lookupM xs j
+        Nothing -> return Nothing
+
+-- | A 'G.Graph' with one root from which all other graph nodes should
+-- be accesible.
+data DAWG a = DAWG
+    { graph :: !(Graph a)
+    , root  :: !Id }
+    deriving (Show, Eq, Ord)
+
+instance (Binary a, Ord a) => Binary (DAWG a) where
+    put d = do
+        put (graph d)
+        put (root d)
+    get = DAWG <$> get <*> get
+
+-- | Empty DAWG.
+empty :: DAWG a
+empty = DAWG G.empty 0
+
+-- | DAWG size (number of nodes).
+size :: DAWG a -> Int
+size = G.size . graph
+
+-- | Insert the (key, value) pair into the DAWG.
+insert :: Ord a => String -> a -> DAWG a -> DAWG a
+insert xs y d =
+    let (i, g) = S.runState (insertM xs y $ root d) (graph d)
+    in  DAWG g i
+
+-- | Find value associated with the key.
+lookup :: String -> DAWG a -> Maybe a
+lookup xs d = S.evalState (lookupM xs $ root d) (graph d)
+
+-- | Construct DAWG from the list of (word, value) pairs.
+fromList :: (Ord a) => [(String, a)] -> DAWG a
+fromList xs =
+    let update t (x, v) = insert x v t
+    in  foldl' update empty xs
+
+-- | Make DAWG from the list of words.  Annotate each word with
+-- the @()@ value.
+fromLang :: [String] -> DAWG ()
+fromLang xs = fromList [(x, ()) | x <- xs]
diff --git a/Data/DAWG/Graph.hs b/Data/DAWG/Graph.hs
new file mode 100644
--- /dev/null
+++ b/Data/DAWG/Graph.hs
@@ -0,0 +1,167 @@
+{-# LANGUAGE RecordWildCards #-}
+
+-- | The module provides a /directed acyclic graph/ (DAG) implementation
+-- where all equivalent nodes (i.e. roots of DAGs equal with respect to
+-- the '==' function) are compressed to one node with unique identifier.
+-- It can be alternatively thought of as a
+-- /minimal acyclic finite-state automata/.
+
+module Data.DAWG.Graph
+( 
+-- * Node
+  Node (..)
+, Id
+, leaf
+, onChar
+, subst
+-- * Graph
+, Graph (..)
+, empty
+, size
+, nodeBy
+, nodeID
+, insert
+, delete
+) where
+
+import Control.Applicative ((<$>), (<*>))
+import Data.Binary (Binary, put, get)
+import qualified Data.Map.Strict as M
+import qualified Data.IntSet as IS
+import qualified Data.IntMap.Strict as IM
+
+import qualified Data.DAWG.VMap as V
+
+-- | Node identifier.
+type Id = Int
+
+-- | Two nodes (states) belong to the same equivalence class (and,
+-- consequently, they must be represented as one node in the graph)
+-- iff they are equal with respect to their values and outgoing
+-- edges.
+data Node a = Node
+    { value :: Maybe a
+    , edges :: V.VMap Id }
+    deriving (Show, Eq, Ord)
+
+instance Binary a => Binary (Node a) where
+    put Node{..} = put value >> put edges
+    get = Node <$> get <*> get
+
+-- | Leaf node with no children and 'Nothing' value.
+leaf :: Node a
+leaf = Node
+    { value = Nothing
+    , edges = V.empty }
+
+-- | Child identifier found by following the given character.
+onChar :: Char -> Node a -> Maybe Id
+onChar x n = V.lookup x (edges n)
+
+-- | Substitue the identifier of the child determined by the given
+-- character.
+subst :: Char -> Id -> Node a -> Node a
+subst x i n = n { edges = V.insert x i (edges n) }
+
+-- | A set of nodes.  To every node a unique identifier is assigned.
+-- Invariants: 
+--
+--   * freeIDs \\intersection occupiedIDs = \\emptySet,
+--
+--   * freeIDs \\sum occupiedIDs =
+--     {0, 1, ..., |freeIDs \\sum occupiedIDs| - 1},
+--
+-- where occupiedIDs = elemSet idMap.
+--
+-- TODO: Is it possible to merge freeIDs with ingoMap to save some memory?
+data Graph a = Graph {
+    -- | Map from nodes to IDs.
+      idMap     :: !(M.Map (Node a) Id)
+    -- | Set of free IDs.
+    , freeIDs   :: !IS.IntSet
+    -- | Equivalence class represented by given ID and size of the class. 
+    , nodeMap   :: !(IM.IntMap (Node a))
+    -- | Number of ingoing edges.
+    , ingoMap   :: !(IM.IntMap Int) }
+    deriving (Show, Eq, Ord)
+
+instance (Binary a, Ord a) => Binary (Graph a) where
+    put Graph{..} = do
+    	put idMap
+	put freeIDs
+	put nodeMap
+	put ingoMap
+    get = Graph <$> get <*> get <*> get <*> get
+
+-- | Empty graph.
+empty :: Graph a
+empty = Graph
+    (M.singleton leaf 0)
+    IS.empty
+    (IM.singleton 0 leaf)
+    (IM.singleton 0 1)
+
+-- | Size of the graph (number of nodes).
+size :: Graph a -> Int
+size = M.size . idMap
+
+-- | Node with the given identifier.
+nodeBy :: Id -> Graph a -> Node a
+nodeBy i g = nodeMap g IM.! i
+
+-- | Retrive the node identifier.
+nodeID :: Ord a => Node a -> Graph a -> Id
+nodeID n g = idMap g M.! n
+
+-- | Add new graph node.
+newNode :: Ord a => Node a -> Graph a -> (Id, Graph a)
+newNode n Graph{..} =
+    (i, Graph idMap' freeIDs' nodeMap' ingoMap')
+  where
+    idMap'      = M.insert  n i idMap
+    nodeMap'    = IM.insert i n nodeMap
+    ingoMap'    = IM.insert i 1 ingoMap
+    (i, freeIDs') = if IS.null freeIDs
+        then (M.size idMap, freeIDs)
+        else IS.deleteFindMin freeIDs
+
+-- | Remove node from the graph.
+remNode :: Ord a => Id -> Graph a -> Graph a
+remNode i Graph{..} =
+    Graph idMap' freeIDs' nodeMap' ingoMap'
+  where
+    idMap'      = M.delete  n idMap
+    nodeMap'    = IM.delete i nodeMap
+    ingoMap'    = IM.delete i ingoMap
+    freeIDs'    = IS.insert i freeIDs
+    n           = nodeMap IM.! i
+
+-- | Increment the number of ingoing edges.
+incIngo :: Id -> Graph a -> Graph a
+incIngo i g = g { ingoMap = IM.adjust (+1) i (ingoMap g) }
+
+-- | Descrement the number of ingoing edges and return
+-- the resulting number.
+decIngo :: Id -> Graph a -> (Int, Graph a)
+decIngo i g =
+    let k = (ingoMap g IM.! i) - 1
+    in  (k, g { ingoMap = IM.insert i k (ingoMap g) })
+
+-- | Insert node into the graph.  If the node was already a member
+-- of the graph, just increase the number of ingoing edges.
+insert :: Ord a => Node a -> Graph a -> (Id, Graph a)
+insert n g = case M.lookup n (idMap g) of
+    Just i  -> (i, incIngo i g)
+    Nothing -> newNode n g
+
+-- | Delete node from the graph.  If the node was present in the graph
+-- at multiple positions, just decrease the number of ingoing edges.
+-- NOTE: The function does not delete descendant nodes which may become
+-- inaccesible.
+delete :: Ord a => Node a -> Graph a -> Graph a
+delete n g = if num == 0
+    then remNode i g'
+    else g'
+  where
+    i = nodeID n g
+    (num, g') = decIngo i g
diff --git a/Data/DAWG/VMap.hs b/Data/DAWG/VMap.hs
new file mode 100644
--- /dev/null
+++ b/Data/DAWG/VMap.hs
@@ -0,0 +1,51 @@
+-- | A vector representation of 'M.Map'.
+
+module Data.DAWG.VMap
+( VMap (unVMap)
+, mkVMap
+, empty
+, lookup
+, insert
+) where
+
+import Prelude hiding (lookup)
+import Control.Applicative ((<$>))
+import Data.Binary (Binary, put, get)
+import Data.Vector.Binary ()
+import qualified Data.Map as M
+import qualified Data.Vector.Unboxed as U
+
+-- | A strictly ascending vector of distinct elements with respect
+-- to 'fst' values.
+newtype VMap a = VMap { unVMap :: U.Vector (Char, a) }
+    deriving (Show, Eq, Ord)
+
+instance (Binary a, U.Unbox a) => Binary (VMap a) where
+    put v = put (unVMap v)
+    get = VMap <$> get
+
+-- | Smart VMap constructor which ensures that the underlying vector is
+-- strictly ascending with respect to 'fst' values.
+mkVMap :: U.Unbox a => [(Char, a)] -> VMap a
+mkVMap = VMap . U.fromList . M.toAscList  . M.fromList 
+{-# INLINE mkVMap #-}
+
+-- | Empty map.
+empty :: U.Unbox a => VMap a
+empty = VMap U.empty
+{-# INLINE empty #-}
+
+-- | Lookup the character in the map.
+lookup :: U.Unbox a => Char -> VMap a -> Maybe a
+lookup x = fmap snd . U.find ((==x) . fst) . unVMap
+{-# INLINE lookup #-}
+
+-- | Insert the (character, value) pair into the map.
+-- TODO: Optimize!  Use the invariant, that VMap is
+-- kept in an ascending vector.
+insert :: U.Unbox a => Char -> a -> VMap a -> VMap a
+insert x y
+    = VMap . U.fromList . M.toAscList
+    . M.insert x y
+    . M.fromList . U.toList . unVMap
+{-# INLINE insert #-}
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2012, IPI PAN
+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.
+
+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.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
diff --git a/dawg.cabal b/dawg.cabal
new file mode 100644
--- /dev/null
+++ b/dawg.cabal
@@ -0,0 +1,35 @@
+name:               dawg
+version:            0.1.0
+synopsis:           DAWG
+description:
+    Directed acyclic word graphs.
+license:            BSD3
+license-file:       LICENSE
+cabal-version:      >= 1.6
+copyright:          Copyright (c) 2012 IPI PAN
+author:             Jakub Waszczuk
+maintainer:         waszczuk.kuba@gmail.com
+stability:          experimental
+category:           Data, Data Structures
+homepage:           https://github.com/kawu/dawg
+build-type:         Simple
+
+library
+    build-depends:
+        base >= 4 && < 5
+      , containers >= 0.5 && < 0.6
+      , binary
+      , vector
+      , vector-binary
+      , mtl
+
+    exposed-modules:
+        Data.DAWG
+      , Data.DAWG.Graph
+      , Data.DAWG.VMap
+
+    ghc-options: -Wall
+
+source-repository head
+    type: git
+    location: https://github.com/kawu/dawg.git
