diff --git a/README.md b/README.md
deleted file mode 100644
--- a/README.md
+++ /dev/null
diff --git a/dawg.cabal b/dawg.cabal
--- a/dawg.cabal
+++ b/dawg.cabal
@@ -1,54 +1,55 @@
-cabal-version: 1.12
+name:               dawg
+version:            0.11
+synopsis:           Directed acyclic word graphs
+description:
+    The library implements /directed acyclic word graphs/ (DAWGs) internally
+    represented as /minimal acyclic deterministic finite-state automata/.
+    .
+    The "Data.DAWG.Dynamic" module provides fast insert and delete operations
+    which can be used to build the automaton on-the-fly.  The automaton from
+    the "Data.DAWG.Static" module has lower memory footprint and provides
+    static hashing functionality.
+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
 
--- This file has been generated from package.yaml by hpack version 0.31.1.
---
--- see: https://github.com/sol/hpack
---
--- hash: 5573d3f5ed5f3dad8d4c64b5f23df1efff78ab4e890fccbe657bd46c4cb550e8
+library
+    hs-source-dirs: src
+    build-depends:
+        base >= 4 && < 5
+      , containers >= 0.4.1 && < 0.6
+      , binary
+      , vector
+      , vector-binary
+      , mtl
+      , transformers
 
-name:           dawg
-version:        0.8.2
-synopsis:       Directed acyclic word graphs
-description:    Please see the README on GitHub at <https://github.com/kawu/dawg#readme>
-category:       Data, Data Structures
-homepage:       https://github.com/kawu/dawg#readme
-bug-reports:    https://github.com/kawu/dawg/issues
-author:         Jakub Waszczuk
-maintainer:     waszczuk.kuba@gmail.com
-copyright:      2012-2019 IPI PAN, Jakub Waszczuk
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-extra-source-files:
-    README.md
+    exposed-modules:
+        Data.DAWG.Dynamic
+      , Data.DAWG.Static
 
-source-repository head
-  type: git
-  location: https://github.com/kawu/dawg
+    other-modules:
+        Data.DAWG.Types
+      , Data.DAWG.Static.Node
+      , Data.DAWG.Dynamic.Internal
+      , Data.DAWG.Dynamic.Node
+      , Data.DAWG.Graph
+      , Data.DAWG.Trans
+      , Data.DAWG.Trans.Vector
+      , Data.DAWG.Trans.Map
+      , Data.DAWG.Trans.Hashed
+      , Data.DAWG.HashMap
+      , Data.DAWG.Util
 
-library
-  exposed-modules:
-      Data.DAWG
-      Data.DAWG.Graph
-      Data.DAWG.HashMap
-      Data.DAWG.Internal
-      Data.DAWG.Node
-      Data.DAWG.Static
-      Data.DAWG.Trans
-      Data.DAWG.Trans.Hashed
-      Data.DAWG.Trans.Map
-      Data.DAWG.Trans.Vector
-      Data.DAWG.Types
-      Data.DAWG.Util
-  other-modules:
-      Paths_dawg
-  hs-source-dirs:
-      src
-  build-depends:
-      base >=4 && <5
-    , binary
-    , containers >=0.5 && <0.7
-    , mtl
-    , vector
-    , vector-binary-instances
-  default-language: Haskell2010
+    ghc-options: -Wall -O2
+
+source-repository head
+    type: git
+    location: https://github.com/kawu/dawg.git
diff --git a/src/Data/DAWG.hs b/src/Data/DAWG.hs
deleted file mode 100644
--- a/src/Data/DAWG.hs
+++ /dev/null
@@ -1,41 +0,0 @@
--- | The module implements /directed acyclic word graphs/ (DAWGs) internaly
--- represented as /minimal acyclic deterministic finite-state automata/.
--- The implementation provides fast insert and delete operations
--- which can be used to build the DAWG structure incrementaly.
---
--- Transition backend has to be specified by a type signature.  You can import
--- the desired transition type and define your own dictionary construction
--- function.
---
--- > import Data.DAWG
--- > import Data.DAWG.Trans.Map (Trans)
--- >
--- > mkDict :: (Enum a, Ord b) => [([a], b)] -> DAWG Trans a b
--- > mkDict = fromList
-
-module Data.DAWG
-(
--- * DAWG type
-  DAWG
-, MkNode
--- * Query
-, numStates
-, lookup
--- * Construction
-, empty
-, fromList
-, fromListWith
-, fromLang
--- ** Insertion
-, insert
-, insertWith
--- ** Deletion
-, delete
--- * Conversion
-, assocs
-, keys
-, elems
-) where
-
-import Prelude hiding (lookup)
-import Data.DAWG.Internal
diff --git a/src/Data/DAWG/Dynamic.hs b/src/Data/DAWG/Dynamic.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DAWG/Dynamic.hs
@@ -0,0 +1,275 @@
+{-# LANGUAGE RecordWildCards #-}
+
+
+-- | The module implements /directed acyclic word graphs/ (DAWGs) internaly
+-- represented as /minimal acyclic deterministic finite-state automata/.
+-- The implementation provides fast insert and delete operations
+-- which can be used to build the DAWG structure incrementaly.
+
+
+module Data.DAWG.Dynamic
+(
+-- * DAWG type
+  DAWG
+
+-- * Query
+, lookup
+, numStates
+, numEdges
+
+-- * Construction
+, empty
+, fromList
+, fromListWith
+, fromLang
+-- ** Insertion
+, insert
+, insertWith
+-- ** Deletion
+, delete
+
+-- * Conversion
+, assocs
+, keys
+, elems
+) where
+
+
+import Prelude hiding (lookup)
+import Control.Applicative ((<$>), (<*>))
+import Control.Arrow (first)
+import Data.List (foldl')
+import qualified Control.Monad.State.Strict as S
+import           Control.Monad.Trans.Maybe
+import           Control.Monad.Trans.Class
+
+import Data.DAWG.Types
+import Data.DAWG.Graph (Graph)
+import Data.DAWG.Dynamic.Internal
+import qualified Data.DAWG.Trans as T
+import qualified Data.DAWG.Graph as G
+import qualified Data.DAWG.Dynamic.Node as N
+
+
+type GraphM a = S.State (Graph (N.Node a))
+
+mkState :: (Graph a -> Graph a) -> Graph a -> ((), Graph a)
+mkState f g = ((), f g)
+
+-- | Return node with the given identifier.
+nodeBy :: ID -> GraphM a (N.Node a)
+nodeBy i = G.nodeBy i <$> S.get
+
+-- Evaluate the 'G.insert' function within the monad.
+insertNode :: Ord a => N.Node a -> GraphM a ID
+insertNode = S.state . G.insert
+
+-- | Leaf node with no children and 'Nothing' value.
+insertLeaf :: Ord a => GraphM a ID
+insertLeaf = do
+    i <- insertNode (N.Leaf Nothing)
+    insertNode (N.Branch i T.empty)
+
+-- Evaluate the 'G.delete' function within the monad.
+deleteNode :: Ord a => N.Node a -> GraphM a ()
+deleteNode = S.state . mkState . G.delete
+
+-- | Invariant: the identifier points to the 'Branch' node.
+insertM :: Ord a => [Sym] -> a -> ID -> GraphM a ID
+insertM (x:xs) y i = do
+    n <- nodeBy i
+    j <- case N.onSym x n of
+        Just j  -> return j
+        Nothing -> insertLeaf
+    k <- insertM xs y j
+    deleteNode n
+    insertNode (N.insert x k n)
+insertM [] y i = do
+    n <- nodeBy i
+    w <- nodeBy (N.eps n)
+    deleteNode w
+    deleteNode n
+    j <- insertNode (N.Leaf $ Just y)
+    insertNode (n { N.eps = j })
+
+insertWithM
+    :: Ord a => (a -> a -> a)
+    -> [Sym] -> a -> ID -> GraphM a ID
+insertWithM f (x:xs) y i = do
+    n <- nodeBy i
+    j <- case N.onSym x n of
+        Just j  -> return j
+        Nothing -> insertLeaf
+    k <- insertWithM f xs y j
+    deleteNode n
+    insertNode (N.insert x k n)
+insertWithM f [] y i = do
+    n <- nodeBy i
+    w <- nodeBy (N.eps n)
+    deleteNode w
+    deleteNode n
+    let y'new = case N.value w of
+            Just y' -> f y y'
+            Nothing -> y
+    j <- insertNode (N.Leaf $ Just y'new)
+    insertNode (n { N.eps = j })
+
+deleteM :: Ord a => [Sym] -> ID -> GraphM a ID
+deleteM (x:xs) i = do
+    n <- nodeBy i
+    case N.onSym x n of
+        Nothing -> return i
+        Just j  -> do
+            k <- deleteM xs j
+            deleteNode n
+            insertNode (N.insert x k n)
+deleteM [] i = do
+    n <- nodeBy i
+    w <- nodeBy (N.eps n)
+    deleteNode w
+    deleteNode n
+    j <- insertLeaf
+    insertNode (n { N.eps = j })
+
+-- | Follow the path from the given identifier.
+follow :: [Sym] -> ID -> MaybeT (GraphM a) ID
+follow (x:xs) i = do
+    n <- lift $ nodeBy i
+    j <- liftMaybe $ N.onSym x n
+    follow xs j
+follow [] i = return i
+    
+lookupM :: [Sym] -> ID -> GraphM a (Maybe a)
+lookupM xs i = runMaybeT $ do
+    j <- follow xs i
+    k <- lift $ N.eps <$> nodeBy j
+    MaybeT $ N.value <$> nodeBy k
+
+-- | Return all (key, value) pairs in ascending key order in the
+-- sub-DAWG determined by the given node ID.
+subPairs :: Graph (N.Node a) -> ID -> [([Sym], a)]
+subPairs g i =
+    here w ++ concatMap there (N.edges n)
+  where
+    n = G.nodeBy i g
+    w = G.nodeBy (N.eps n) g
+    here v = case N.value v of
+        Just x  -> [([], x)]
+        Nothing -> []
+    there (sym, j) = map (first (sym:)) (subPairs g j)
+
+-- | Empty DAWG.
+empty :: Ord b => DAWG a b
+empty = 
+    let (i, g) = S.runState insertLeaf G.empty
+    in  DAWG g i
+
+-- | Number of states in the automaton.
+numStates :: DAWG a b -> Int
+numStates = G.size . graph
+
+-- | Number of edges in the automaton.
+numEdges :: DAWG a b -> Int
+numEdges = sum . map (length . N.edges) . G.nodes . graph
+
+-- | Insert the (key, value) pair into the DAWG.
+insert :: (Enum a, Ord b) => [a] -> b -> DAWG a b -> DAWG a b
+insert xs' y d =
+    let xs = map fromEnum xs'
+        (i, g) = S.runState (insertM xs y $ root d) (graph d)
+    in  DAWG g i
+{-# INLINE insert #-}
+
+-- | Insert with a function, combining new value and old value.
+-- 'insertWith' f key value d will insert the pair (key, value) into d if
+-- key does not exist in the DAWG. If the key does exist, the function
+-- will insert the pair (key, f new_value old_value).
+insertWith
+    :: (Enum a, Ord b) => (b -> b -> b)
+    -> [a] -> b -> DAWG a b -> DAWG a b
+insertWith f xs' y d =
+    let xs = map fromEnum xs'
+        (i, g) = S.runState (insertWithM f xs y $ root d) (graph d)
+    in  DAWG g i
+{-# SPECIALIZE insertWith
+        :: Ord b => (b -> b -> b) -> String -> b
+        -> DAWG Char b -> DAWG Char b #-}
+
+-- | Delete the key from the DAWG.
+delete :: (Enum a, Ord b) => [a] -> DAWG a b -> DAWG a b
+delete xs' d =
+    let xs = map fromEnum xs'
+        (i, g) = S.runState (deleteM xs $ root d) (graph d)
+    in  DAWG g i
+{-# SPECIALIZE delete :: Ord b => String -> DAWG Char b -> DAWG Char b #-}
+
+-- | Find value associated with the key.
+lookup :: (Enum a, Ord b) => [a] -> DAWG a b -> Maybe b
+lookup xs' d =
+    let xs = map fromEnum xs'
+    in  S.evalState (lookupM xs $ root d) (graph d)
+{-# SPECIALIZE lookup :: Ord b => String -> DAWG Char b -> Maybe b #-}
+
+-- -- | Find all (key, value) pairs such that key is prefixed
+-- -- with the given string.
+-- withPrefix :: (Enum a, Ord b) => [a] -> DAWG a b -> [([a], b)]
+-- withPrefix xs DAWG{..}
+--     = map (first $ (xs ++) . map toEnum)
+--     $ maybe [] (subPairs graph)
+--     $ flip S.evalState graph $ runMaybeT
+--     $ follow (map fromEnum xs) root
+-- {-# SPECIALIZE withPrefix
+--     :: Ord b => String -> DAWG Char b
+--     -> [(String, b)] #-}
+
+-- | Return all key/value pairs in the DAWG in ascending key order.
+assocs :: (Enum a, Ord b) => DAWG a b -> [([a], b)]
+assocs
+    = map (first (map toEnum))
+    . (subPairs <$> graph <*> root)
+{-# SPECIALIZE assocs :: Ord b => DAWG Char b -> [(String, b)] #-}
+
+-- | Return all keys of the DAWG in ascending order.
+keys :: (Enum a, Ord b) => DAWG a b -> [[a]]
+keys = map fst . assocs
+{-# SPECIALIZE keys :: Ord b => DAWG Char b -> [String] #-}
+
+-- | Return all elements of the DAWG in the ascending order of their keys.
+elems :: Ord b => DAWG a b -> [b]
+elems = map snd . (subPairs <$> graph <*> root)
+
+-- | Construct DAWG from the list of (word, value) pairs.
+fromList :: (Enum a, Ord b) => [([a], b)] -> DAWG a b
+fromList xs =
+    let update t (x, v) = insert x v t
+    in  foldl' update empty xs
+{-# INLINE fromList #-}
+
+-- | Construct DAWG from the list of (word, value) pairs
+-- with a combining function.  The combining function is
+-- applied strictly.
+fromListWith
+    :: (Enum a, Ord b) => (b -> b -> b)
+    -> [([a], b)] -> DAWG a b
+fromListWith f xs =
+    let update t (x, v) = insertWith f x v t
+    in  foldl' update empty xs
+{-# SPECIALIZE fromListWith
+        :: Ord b => (b -> b -> b)
+        -> [(String, b)] -> DAWG Char b #-}
+
+-- | Make DAWG from the list of words.  Annotate each word with
+-- the @()@ value.
+fromLang :: Enum a => [[a]] -> DAWG a ()
+fromLang xs = fromList [(x, ()) | x <- xs]
+{-# SPECIALIZE fromLang :: [String] -> DAWG Char () #-}
+
+
+----------------
+-- Misc
+----------------
+
+
+liftMaybe :: Monad m => Maybe a -> MaybeT m a
+liftMaybe = MaybeT . return
+{-# INLINE liftMaybe #-}
diff --git a/src/Data/DAWG/Dynamic/Internal.hs b/src/Data/DAWG/Dynamic/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DAWG/Dynamic/Internal.hs
@@ -0,0 +1,27 @@
+-- | The module exports internal representation of dynamic DAWG.
+
+module Data.DAWG.Dynamic.Internal
+(
+-- * DAWG type
+  DAWG (..)
+) where
+
+import Control.Applicative ((<$>), (<*>))
+import Data.Binary (Binary, put, get)
+
+import Data.DAWG.Types
+import Data.DAWG.Graph (Graph)
+import qualified Data.DAWG.Dynamic.Node as N
+
+-- | A directed acyclic word graph with phantom type @a@ representing
+-- type of alphabet elements.
+data DAWG a b = DAWG
+    { graph :: !(Graph (N.Node b))
+    , root  :: !ID }
+    deriving (Show, Eq, Ord)
+
+instance (Ord b, Binary b) => Binary (DAWG a b) where
+    put d = do
+        put (graph d)
+        put (root d)
+    get = DAWG <$> get <*> get
diff --git a/src/Data/DAWG/Dynamic/Node.hs b/src/Data/DAWG/Dynamic/Node.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DAWG/Dynamic/Node.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE RecordWildCards #-}
+
+-- | Internal representation of dynamic automata nodes.
+
+module Data.DAWG.Dynamic.Node
+( Node(..)
+, onSym
+, edges
+, children
+, insert
+) where
+
+import Control.Applicative ((<$>), (<*>))
+import Data.Binary (Binary, Get, put, get)
+
+import Data.DAWG.Types
+import Data.DAWG.Util (combine)
+import Data.DAWG.HashMap (Hash, hash)
+import Data.DAWG.Trans.Map (Trans)
+import qualified Data.DAWG.Trans as T
+import qualified Data.DAWG.Trans.Hashed as H
+
+-- | 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.
+--
+-- Since 'Leaf' nodes are distinguished from 'Branch' nodes, two values
+-- equal with respect to '==' function are always kept in one 'Leaf'
+-- node in the graph.  It doesn't change the fact that to all 'Branch'
+-- nodes one value is assigned through the epsilon transition.
+--
+-- Invariant: the 'eps' identifier always points to the 'Leaf' node.
+-- Edges in the 'edgeMap', on the other hand, point to 'Branch' nodes.
+data Node a
+    = Branch {
+        -- | Epsilon transition.
+          eps       :: {-# UNPACK #-} !ID
+        -- | Transition map (outgoing edges).
+        , transMap  :: !(H.Hashed Trans) }
+    | Leaf { value  :: !(Maybe a) }
+    deriving (Show, Eq, Ord)
+
+instance Ord a => Hash (Node a) where
+    hash Branch{..} = combine eps (H.hash transMap)
+    hash Leaf{..}   = case value of
+    	Just _	-> (-1)
+	Nothing	-> (-2)
+
+instance Binary a => Binary (Node a) where
+    put Branch{..} = put (1 :: Int) >> put eps >> put transMap
+    put Leaf{..}   = put (2 :: Int) >> put value
+    get = do
+        x <- get :: Get Int
+        case x of
+            1 -> Branch <$> get <*> get
+            _ -> Leaf <$> get
+
+-- | Transition function.
+onSym :: Sym -> Node a -> Maybe ID
+onSym x (Branch _ t)    = T.lookup x t
+onSym _ (Leaf _)        = Nothing
+{-# INLINE onSym #-}
+
+-- | List of symbol/edge pairs outgoing from the node.
+edges :: Node a -> [(Sym, ID)]
+edges (Branch _ t)  = T.toList t
+edges (Leaf _)      = []
+{-# INLINE edges #-}
+
+-- | List of children identifiers.
+children :: Node a -> [ID]
+children = map snd . edges
+{-# INLINE children #-}
+
+-- | Substitue edge determined by a given symbol.
+insert :: Sym -> ID -> Node a -> Node a
+insert x i (Branch w t) = Branch w (T.insert x i t)
+insert _ _ l            = l
+{-# INLINE insert #-}
diff --git a/src/Data/DAWG/Graph.hs b/src/Data/DAWG/Graph.hs
--- a/src/Data/DAWG/Graph.hs
+++ b/src/Data/DAWG/Graph.hs
@@ -9,6 +9,7 @@
 ( Graph (..)
 , empty
 , size
+, nodes
 , nodeBy
 , insert
 , delete
@@ -17,7 +18,7 @@
 import Control.Applicative ((<$>), (<*>))
 import Data.Binary (Binary, put, get)
 import qualified Data.IntSet as S
-import qualified Data.IntMap.Strict as M
+import qualified Data.IntMap as M
 
 import Data.DAWG.HashMap (Hash)
 import qualified Data.DAWG.HashMap as H
@@ -68,6 +69,10 @@
 size :: Graph n -> Int
 size = H.size . idMap
 
+-- | List of graph nodes.
+nodes :: Graph n -> [n]
+nodes = M.elems . nodeMap
+
 -- | Node with the given identifier.
 nodeBy :: ID -> Graph n -> n
 nodeBy i g = nodeMap g M.! i
@@ -105,7 +110,7 @@
 
 -- | Increment the number of ingoing paths.
 incIngo :: ID -> Graph n -> Graph n
-incIngo i g = g { ingoMap = M.insertWith (+) i 1 (ingoMap g) }
+incIngo i g = g { ingoMap = M.insertWith' (+) i 1 (ingoMap g) }
 
 -- | Decrement the number of ingoing paths and return
 -- the resulting number.
diff --git a/src/Data/DAWG/HashMap.hs b/src/Data/DAWG/HashMap.hs
--- a/src/Data/DAWG/HashMap.hs
+++ b/src/Data/DAWG/HashMap.hs
@@ -51,7 +51,7 @@
 
 -- | Assumption: element is a member of the 'Value'. 
 findUnsafe :: Ord a => a -> Value a b -> Maybe b
-findUnsafe _ (Single _ y) = Just y     -- unsafe
+findUnsafe _ (Single _ y) = Just y	-- unsafe
 findUnsafe x (Multi m) = M.lookup x m
 
 -- | Convert map into a 'Single' form if possible.
diff --git a/src/Data/DAWG/Internal.hs b/src/Data/DAWG/Internal.hs
deleted file mode 100644
--- a/src/Data/DAWG/Internal.hs
+++ /dev/null
@@ -1,269 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-
--- | The module implements /directed acyclic word graphs/ (DAWGs) internaly
--- represented as /minimal acyclic deterministic finite-state automata/.
--- The implementation provides fast insert and delete operations
--- which can be used to build the DAWG structure incrementaly.
-
-module Data.DAWG.Internal
-(
--- * DAWG type
-  DAWG (..)
-, MkNode
--- * Query
-, numStates
-, lookup
--- * Construction
-, empty
-, fromList
-, fromListWith
-, fromLang
--- ** Insertion
-, insert
-, insertWith
--- ** Deletion
-, delete
--- * Conversion
-, assocs
-, keys
-, elems
-) where
-
-import Prelude hiding (lookup)
-import Control.Applicative ((<$>), (<*>))
-import Control.Arrow (first)
-import Data.List (foldl')
-import Data.Binary (Binary, put, get)
-import qualified Data.Vector.Unboxed as U
-import qualified Control.Monad.State.Strict as S
-
-import Data.DAWG.Types
-import Data.DAWG.Graph (Graph)
-import Data.DAWG.Trans (Trans)
-import qualified Data.DAWG.Trans as T
-import qualified Data.DAWG.Node as N
-import qualified Data.DAWG.Graph as G
-
-type Node t a = N.Node t () a
-
--- | Is /t/ a valid transition map within the context of
--- /a/-valued automata nodes?  All transition implementations
--- provided by the library are instances of this class.
-class (Ord (Node t a), Trans t) => MkNode t a where
-instance (Ord (Node t a), Trans t) => MkNode t a where
-
-type GraphM t a b = S.State (Graph (Node t a)) b
-
-mkState :: (Graph a -> Graph a) -> Graph a -> ((), Graph a)
-mkState f g = ((), f g)
-
--- | Leaf node with no children and 'Nothing' value.
-insertLeaf :: MkNode t a => GraphM t a ID
-insertLeaf = do
-    i <- insertNode (N.Leaf Nothing)
-    insertNode (N.Branch i T.empty U.empty)
-
--- | Return node with the given identifier.
-nodeBy :: ID -> GraphM t a (Node t a)
-nodeBy i = G.nodeBy i <$> S.get
-
--- Evaluate the 'G.insert' function within the monad.
-insertNode :: MkNode t a => Node t a -> GraphM t a ID
-insertNode = S.state . G.insert
-
--- Evaluate the 'G.delete' function within the monad.
-deleteNode :: MkNode t a => Node t a -> GraphM t a ()
-deleteNode = S.state . mkState . G.delete
-
--- | Invariant: the identifier points to the 'Branch' node.
-insertM :: MkNode t a => [Sym] -> a -> ID -> GraphM t a ID
-insertM (x:xs) y i = do
-    n <- nodeBy i
-    j <- case N.onSym x n of
-        Just j  -> return j
-        Nothing -> insertLeaf
-    k <- insertM xs y j
-    deleteNode n
-    insertNode (N.insert x k n)
-insertM [] y i = do
-    n <- nodeBy i
-    w <- nodeBy (N.eps n)
-    deleteNode w
-    deleteNode n
-    j <- insertNode (N.Leaf $ Just y)
-    insertNode (n { N.eps = j })
-
-insertWithM
-    :: MkNode t a => (a -> a -> a)
-    -> [Sym] -> a -> ID -> GraphM t a ID
-insertWithM f (x:xs) y i = do
-    n <- nodeBy i
-    j <- case N.onSym x n of
-        Just j  -> return j
-        Nothing -> insertLeaf
-    k <- insertWithM f xs y j
-    deleteNode n
-    insertNode (N.insert x k n)
-insertWithM f [] y i = do
-    n <- nodeBy i
-    w <- nodeBy (N.eps n)
-    deleteNode w
-    deleteNode n
-    let y'new = case N.value w of
-            Just y' -> f y y'
-            Nothing -> y
-    j <- insertNode (N.Leaf $ Just y'new)
-    insertNode (n { N.eps = j })
-
-deleteM :: MkNode t a => [Sym] -> ID -> GraphM t a ID
-deleteM (x:xs) i = do
-    n <- nodeBy i
-    case N.onSym x n of
-        Nothing -> return i
-        Just j  -> do
-            k <- deleteM xs j
-            deleteNode n
-            insertNode (N.insert x k n)
-deleteM [] i = do
-    n <- nodeBy i
-    w <- nodeBy (N.eps n)
-    deleteNode w
-    deleteNode n
-    j <- insertLeaf
-    insertNode (n { N.eps = j })
-    
-lookupM :: Trans t => [Sym] -> ID -> GraphM t a (Maybe a)
-lookupM [] i = do
-    j <- N.eps <$> nodeBy i
-    N.value <$> nodeBy j
-lookupM (x:xs) i = do
-    n <- nodeBy i
-    case N.onSym x n of
-        Just j  -> lookupM xs j
-        Nothing -> return Nothing
-
-assocsAcc :: Trans t => Graph (Node t a) -> ID -> [([Sym], a)]
-assocsAcc g i =
-    here w ++ concatMap there (N.edges n)
-  where
-    n = G.nodeBy i g
-    w = G.nodeBy (N.eps n) g
-    here v = case N.value v of
-        Just x  -> [([], x)]
-        Nothing -> []
-    there (sym, j) = map (first (sym:)) (assocsAcc g j)
-
--- | A directed acyclic word graph with phantom type @a@ representing
--- type of alphabet elements.
-data DAWG t a b = DAWG
-    { graph :: !(Graph (Node t b))
-    , root  :: !ID }
-    deriving (Show)
-
-instance (MkNode t b, Binary t, Binary b) => Binary (DAWG t a b) where
-    put d = do
-        put (graph d)
-        put (root d)
-    get = DAWG <$> get <*> get
-
--- | Empty DAWG.
-empty :: (MkNode t b) => DAWG t a b
-empty = 
-    let (i, g) = S.runState insertLeaf G.empty
-    in  DAWG g i
-
--- | Number of states in the underlying graph.
-numStates :: DAWG t a b -> Int
-numStates = G.size . graph
-
--- | Insert the (key, value) pair into the DAWG.
-insert :: (Enum a, MkNode t b) => [a] -> b -> DAWG t a b -> DAWG t a b
-insert xs' y d =
-    let xs = map fromEnum xs'
-        (i, g) = S.runState (insertM xs y $ root d) (graph d)
-    in  DAWG g i
-{-# INLINE insert #-}
-{-# SPECIALIZE insert
-        :: (MkNode t b) => String -> b
-        -> DAWG t Char b -> DAWG t Char b #-}
-
--- | Insert with a function, combining new value and old value.
--- 'insertWith' f key value d will insert the pair (key, value) into d if
--- key does not exist in the DAWG. If the key does exist, the function
--- will insert the pair (key, f new_value old_value).
-insertWith
-    :: (Enum a, MkNode t b) => (b -> b -> b)
-    -> [a] -> b -> DAWG t a b -> DAWG t a b
-insertWith f xs' y d =
-    let xs = map fromEnum xs'
-        (i, g) = S.runState (insertWithM f xs y $ root d) (graph d)
-    in  DAWG g i
-{-# SPECIALIZE insertWith
-        :: MkNode t b => (b -> b -> b) -> String -> b
-        -> DAWG t Char b -> DAWG t Char b #-}
-
--- | Delete the key from the DAWG.
-delete :: (Enum a, MkNode t b) => [a] -> DAWG t a b -> DAWG t a b
-delete xs' d =
-    let xs = map fromEnum xs'
-        (i, g) = S.runState (deleteM xs $ root d) (graph d)
-    in  DAWG g i
-{-# SPECIALIZE delete
-        :: MkNode t b => String
-        -> DAWG t Char b -> DAWG t Char b #-}
-
--- | Find value associated with the key.
-lookup :: (Enum a, MkNode t b) => [a] -> DAWG t a b -> Maybe b
-lookup xs' d =
-    let xs = map fromEnum xs'
-    in  S.evalState (lookupM xs $ root d) (graph d)
-{-# SPECIALIZE lookup
-        :: MkNode t b => String
-        -> DAWG t Char b -> Maybe b #-}
-
--- | Return all key/value pairs in the DAWG in ascending key order.
-assocs :: (Enum a, MkNode t b) => DAWG t a b -> [([a], b)]
-assocs
-    = map (first (map toEnum))
-    . (assocsAcc <$> graph <*> root)
-{-# SPECIALIZE assocs :: MkNode t b => DAWG t Char b -> [(String, b)] #-}
-
--- | Return all keys of the DAWG in ascending order.
-keys :: (Enum a, MkNode t b) => DAWG t a b -> [[a]]
-keys = map fst . assocs
-{-# SPECIALIZE keys :: MkNode t b => DAWG t Char b -> [String] #-}
-
--- | Return all elements of the DAWG in the ascending order of their keys.
-elems :: MkNode t b => DAWG t a b -> [b]
-elems = map snd . (assocsAcc <$> graph <*> root)
-
--- | Construct DAWG from the list of (word, value) pairs.
-fromList :: (Enum a, MkNode t b) => [([a], b)] -> DAWG t a b
-fromList xs =
-    let update t (x, v) = insert x v t
-    in  foldl' update empty xs
-{-# INLINE fromList #-}
-{-# SPECIALIZE fromList
-        :: MkNode t b => [(String, b)] -> DAWG t Char b #-}
-
--- | Construct DAWG from the list of (word, value) pairs
--- with a combining function.  The combining function is
--- applied strictly.
-fromListWith
-    :: (Enum a, MkNode t b) => (b -> b -> b)
-    -> [([a], b)] -> DAWG t a b
-fromListWith f xs =
-    let update t (x, v) = insertWith f x v t
-    in  foldl' update empty xs
-{-# SPECIALIZE fromListWith
-        :: MkNode t b => (b -> b -> b)
-        -> [(String, b)] -> DAWG t Char b #-}
-
--- | Make DAWG from the list of words.  Annotate each word with
--- the @()@ value.
-fromLang :: (Enum a, MkNode t ()) => [[a]] -> DAWG t a ()
-fromLang xs = fromList [(x, ()) | x <- xs]
-{-# SPECIALIZE fromLang :: MkNode t () => [String] -> DAWG t Char () #-}
diff --git a/src/Data/DAWG/Node.hs b/src/Data/DAWG/Node.hs
deleted file mode 100644
--- a/src/Data/DAWG/Node.hs
+++ /dev/null
@@ -1,114 +0,0 @@
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE StandaloneDeriving #-}
-
--- | Internal representation of automata nodes.
-
-module Data.DAWG.Node
-( Node (..)
-, onSym
-, onSym'
-, edges
-, children
-, insert
-, reID
-) where
-
-import Control.Applicative ((<$>), (<*>))
-import Control.Arrow (second)
-import Data.Binary (Binary, Get, put, get)
-import Data.Vector.Binary ()
-import qualified Data.Vector.Unboxed as U
-
-import Data.DAWG.Types
-import Data.DAWG.Util (combine)
-import Data.DAWG.Trans (Trans)
-import Data.DAWG.HashMap (Hash, hash)
-import qualified Data.DAWG.Trans.Hashed as H
-import qualified Data.DAWG.Trans as T
-import qualified Data.DAWG.Trans.Vector as TV
-import qualified Data.DAWG.Trans.Map as TM
-
--- | 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.
---
--- Since 'Leaf' nodes are distinguished from 'Branch' nodes, two values
--- equal with respect to '==' function are always kept in one 'Leaf'
--- node in the graph.  It doesn't change the fact that to all 'Branch'
--- nodes one value is assigned through the epsilon transition.
---
--- Invariant: the 'eps' identifier always points to the 'Leaf' node.
--- Edges in the 'edgeMap', on the other hand, point to 'Branch' nodes.
-data Node t a b
-    = Branch {
-        -- | Epsilon transition.
-          eps       :: {-# UNPACK #-} !ID
-        -- | Transition map (outgoing edges).
-        , transMap  :: !(H.Hashed t)
-        -- | Labels corresponding to individual edges.
-        , labelVect :: !(U.Vector a) }
-    | Leaf { value  :: !(Maybe b) }
-    deriving (Show)
-
-deriving instance (Eq a, Eq b, U.Unbox a)   => Eq (Node TV.Trans a b)
-deriving instance (Ord a, Ord b, U.Unbox a) => Ord (Node TV.Trans a b)
-deriving instance (Eq a, Eq b, U.Unbox a)   => Eq (Node TM.Trans a b)
-deriving instance (Ord a, Ord b, U.Unbox a) => Ord (Node TM.Trans a b)
-
-instance (Trans t, Ord (Node t a b)) => Hash (Node t a b) where
-    hash Branch{..} = combine eps (H.hash transMap)
-    hash Leaf{..}   = case value of
-    	Just _	-> (-1)
-	Nothing	-> (-2)
-
-instance (U.Unbox a, Binary t, Binary a, Binary b) => Binary (Node t a b) where
-    put Branch{..} = put (1 :: Int) >> put eps >> put transMap >> put labelVect
-    put Leaf{..}   = put (2 :: Int) >> put value
-    get = do
-        x <- get :: Get Int
-        case x of
-            1 -> Branch <$> get <*> get <*> get
-            _ -> Leaf <$> get
-
--- | Transition function.
-onSym :: Trans t => Sym -> Node t a b -> Maybe ID
-onSym x (Branch _ t _)  = T.lookup x t
-onSym _ (Leaf _)        = Nothing
-{-# INLINE onSym #-}
-
--- | Transition function.
-onSym' :: (Trans t, U.Unbox a) => Sym -> Node t a b -> Maybe (ID, a)
-onSym' x (Branch _ t ls)   = do
-    k <- T.index x t
-    (,) <$> (snd <$> T.byIndex k t)
-        <*> ls U.!? k
-onSym' _ (Leaf _)           = Nothing
-{-# INLINE onSym' #-}
-
--- | List of symbol/edge pairs outgoing from the node.
-edges :: Trans t => Node t a b -> [(Sym, ID)]
-edges (Branch _ t _)    = T.toList t
-edges (Leaf _)          = []
-{-# INLINE edges #-}
-
--- | List of children identifiers.
-children :: Trans t => Node t a b -> [ID]
-children = map snd . edges
-{-# INLINE children #-}
-
--- | Substitue edge determined by a given symbol.
-insert :: Trans t => Sym -> ID -> Node t a b -> Node t a b
-insert x i (Branch w t ls)  = Branch w (T.insert x i t) ls
-insert _ _ l                = l
-{-# INLINE insert #-}
-
--- | Assign new identifiers.
-reID :: Trans t => (ID -> ID) -> Node t a b -> Node t a b
-reID _ (Leaf x)         = Leaf x
-reID f (Branch e t ls)  =
-    let reTrans = T.fromList . map (second f) . T.toList
-    in  Branch (f e) (reTrans t) ls
diff --git a/src/Data/DAWG/Static.hs b/src/Data/DAWG/Static.hs
--- a/src/Data/DAWG/Static.hs
+++ b/src/Data/DAWG/Static.hs
@@ -1,63 +1,60 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
 
+
 -- | The module implements /directed acyclic word graphs/ (DAWGs) internaly
 -- represented as /minimal acyclic deterministic finite-state automata/.
 --
--- In comparison to "Data.DAWG" module the automaton implemented here:
+-- In comparison to "Data.DAWG.Dynamic" module the automaton implemented here:
 --
---   * Keeps all nodes in one array and therefore uses much less memory,
+--   * Keeps all nodes in one array and therefore uses less memory,
 --
 --   * When 'weigh'ed, it can be used to perform static hashing with
---     'hash' and 'unHash' functions,
+--     'index' and 'byIndex' functions,
 --
 --   * Doesn't provide insert/delete family of operations.
---
--- Transition backend has to be specified by a type signature.  You can import
--- the desired transition type and define your own dictionary construction
--- function.
---
--- > import Data.DAWG.Static
--- > import Data.DAWG.Trans.Map (Trans)
--- >
--- > mkDict :: (Enum a, Ord b) => [([a], b)] -> DAWG Trans a Weight b
--- > mkDict = weigh . fromList
 
+
 module Data.DAWG.Static
 (
 -- * DAWG type
   DAWG
+
+-- * ID
+, ID
+, rootID
+, byID
+
 -- * Query
 , lookup
+, edges
+, submap
 , numStates
--- * Index
+, numEdges
+
+-- * Weight
+, Weight
+, weigh
+, size
 , index
 , byIndex
--- * Hash
-, hash
-, unHash
+
 -- * Construction
 , empty
 , fromList
 , fromListWith
 , fromLang
-, freeze
--- * Weight
-, Weight
-, weigh
+
 -- * Conversion
 , assocs
 , keys
 , elems
+, freeze
 -- , thaw
 ) where
 
+
 import Prelude hiding (lookup)
-import Control.Applicative ((<$), (<$>), (<|>))
+import Control.Applicative ((<$), (<$>), (<*>), (<|>))
 import Control.Arrow (first)
 import Data.Binary (Binary, put, get)
 import Data.Vector.Binary ()
@@ -67,127 +64,191 @@
 import qualified Data.Vector.Unboxed as U
 
 import Data.DAWG.Types
-import Data.DAWG.Trans (Trans)
-import Data.DAWG.Node (Node)
+import qualified Data.DAWG.Util as Util
 import qualified Data.DAWG.Trans as T
-import qualified Data.DAWG.Trans.Vector as VT
-import qualified Data.DAWG.Node as N
+import qualified Data.DAWG.Static.Node as N
 import qualified Data.DAWG.Graph as G
-import qualified Data.DAWG.Internal as D
-import qualified Data.DAWG.Util as Util
+import qualified Data.DAWG.Dynamic as D
+import qualified Data.DAWG.Dynamic.Internal as D
 
--- | @DAWG t a b c@ constitutes an automaton with alphabet symbols of type /a/,
--- transition labels of type /b/ and node values of type /Maybe c/, implemented
--- on top of the 'T.Trans' /t/ backend.  All nodes are stored in a 'V.Vector'
--- with positions of nodes corresponding to their 'ID's.
-newtype DAWG t a b c = DAWG { unDAWG :: V.Vector (Node t b c) }
-    deriving (Show)
 
-deriving instance (Eq b, Eq c, Unbox b)     => Eq  (DAWG VT.Trans a b c)
-deriving instance (Ord b, Ord c, Unbox b)   => Ord (DAWG VT.Trans a b c)
+-- | @DAWG a b c@ constitutes an automaton with alphabet symbols of type /a/,
+-- transition labels of type /b/ and node values of type /Maybe c/.
+-- All nodes are stored in a 'V.Vector' with positions of nodes corresponding
+-- to their 'ID's.
+--
+data DAWG a b c = DAWG
+    { nodes  :: V.Vector (N.Node b c)
+    -- | The actual DAWG root has the 0 ID.  Thanks to the 'rootID'
+    -- attribute, we can represent a submap of a DAWG.
+    , rootID :: ID
+    } deriving (Show, Eq, Ord)
 
-instance (Binary t, Binary b, Binary c, Unbox b) => Binary (DAWG t a b c) where
-    put = put . unDAWG
-    get = DAWG <$> get
+instance (Binary b, Binary c, Unbox b) => Binary (DAWG a b c) where
+    put DAWG{..} = put nodes >> put rootID
+    get = DAWG <$> get <*> get
 
+
+-- | Retrieve sub-DAWG with a given ID (or `Nothing`, if there's
+-- no such DAWG).  This function can be used, together with the
+-- `root` function, to store IDs rather than entire DAWGs in a
+-- data structure.
+byID :: ID -> DAWG a b c -> Maybe (DAWG a b c)
+byID i d = if i >= 0 && i < V.length (nodes d)
+    then Just (d { rootID = i })
+    else Nothing
+
+
 -- | Empty DAWG.
-empty :: (Trans t, Unbox b) => DAWG t a b c
-empty = DAWG $ V.fromList
+empty :: Unbox b => DAWG a b c
+empty = flip DAWG 0 $ V.fromList
     [ N.Branch 1 T.empty U.empty
     , N.Leaf Nothing ]
 
+
+-- | A list of outgoing edges.
+edges :: Enum a => DAWG a b c -> [(a, DAWG a b c)]
+edges d =
+    [ (toEnum sym, d{ rootID = i })
+    | (sym, i) <- N.edges n ]
+  where
+    n = nodeBy (rootID d) d
+
+
+-- | Return the sub-DAWG containing all keys beginning with a prefix.
+-- The in-memory representation of the resultant DAWG is the same as of
+-- the original one, only the pointer to the DAWG root will be different.
+submap :: (Enum a, Unbox b) => [a] -> DAWG a b c -> DAWG a b c
+submap xs d = case follow (map fromEnum xs) (rootID d) d of
+    Just i  -> d { rootID = i }
+    Nothing -> empty
+{-# SPECIALIZE submap :: Unbox b => String -> DAWG Char b c -> DAWG Char b c #-}
+
+
 -- | Number of states in the automaton.
-numStates :: DAWG t a b c -> Int
-numStates = V.length . unDAWG
+-- TODO: The function ignores the `rootID` value, it won't work properly
+-- after using the `submap` function.
+numStates :: DAWG a b c -> Int
+numStates = V.length . nodes
 
+
+-- | Number of edges in the automaton.
+-- TODO: The function ignores the `rootID` value, it won't work properly
+-- after using the `submap` function.
+numEdges :: DAWG a b c -> Int
+numEdges = sum . map (length . N.edges) . V.toList . nodes
+
+
 -- | Node with the given identifier.
-nodeBy :: ID -> DAWG t a b c -> Node t b c
-nodeBy i d = unDAWG d V.! i
+nodeBy :: ID -> DAWG a b c -> N.Node b c
+nodeBy i d = nodes d V.! i
 
+
 -- | Value in leaf node with a given ID.
-leafValue :: Node t b c -> DAWG t a b c -> Maybe c
+leafValue :: N.Node b c -> DAWG a b c -> Maybe c
 leafValue n = N.value . nodeBy (N.eps n)
 
+
+-- | Follow the path from the given identifier.
+follow :: Unbox b => [Sym] -> ID -> DAWG a b c -> Maybe ID
+follow (x:xs) i d = do
+    j <- N.onSym x (nodeBy i d)
+    follow xs j d
+follow [] i _ = Just i
+
+
 -- | Find value associated with the key.
-lookup :: (Enum a, Trans t, Unbox b) => [a] -> DAWG t a b c -> Maybe c
-lookup xs' =
-    let xs = map fromEnum xs'
-    in  lookup'I xs 0
-{-# SPECIALIZE lookup
-        :: (Trans t, Unbox b) => String
-        -> DAWG t Char b c -> Maybe c #-}
+lookup :: (Enum a, Unbox b) => [a] -> DAWG a b c -> Maybe c
+lookup xs d = lookup'I (map fromEnum xs) (rootID d) d
+{-# SPECIALIZE lookup :: Unbox b => String -> DAWG Char b c -> Maybe c #-}
 
-lookup'I :: (Trans t, Unbox b) => [Sym] -> ID -> DAWG t a b c -> Maybe c
-lookup'I []     i d = leafValue (nodeBy i d) d
-lookup'I (x:xs) i d = case N.onSym x (nodeBy i d) of
-    Just j  -> lookup'I xs j d
-    Nothing -> Nothing
 
--- | Return all key/value pairs in the DAWG in ascending key order.
-assocs :: (Enum a, Trans t, Unbox b) => DAWG t a b c -> [([a], c)]
-assocs d = map (first (map toEnum)) (assocs'I 0 d)
-{-# SPECIALIZE assocs
-        :: (Trans t, Unbox b)
-        => DAWG t Char b c -> [(String, c)] #-}
+lookup'I :: Unbox b => [Sym] -> ID -> DAWG a b c -> Maybe c
+lookup'I xs i d = do
+    j <- follow xs i d
+    leafValue (nodeBy j d) d
 
-assocs'I :: (Trans t, Unbox b) => ID -> DAWG t a b c -> [([Sym], c)]
-assocs'I i d =
+
+-- -- | Find all (key, value) pairs such that key is prefixed
+-- -- with the given string.
+-- withPrefix :: (Enum a, Unbox b) => [a] -> DAWG a b c -> [([a], c)]
+-- withPrefix xs d = maybe [] id $ do
+--     i <- follow (map fromEnum xs) 0 d
+--     let prepare = (xs ++) . map toEnum
+--     return $ map (first prepare) (subPairs i d)
+-- {-# SPECIALIZE withPrefix
+--     :: Unbox b => String -> DAWG Char b c
+--     -> [(String, c)] #-}
+
+
+-- | Return all (key, value) pairs in ascending key order in the
+-- sub-DAWG determined by the given node ID.
+subPairs :: Unbox b => ID -> DAWG a b c -> [([Sym], c)]
+subPairs i d =
     here ++ concatMap there (N.edges n)
   where
     n = nodeBy i d
     here = case leafValue n d of
         Just x  -> [([], x)]
         Nothing -> []
-    there (x, j) = map (first (x:)) (assocs'I j d)
+    there (x, j) = map (first (x:)) (subPairs j d)
 
+
+-- | Return all (key, value) pairs in the DAWG in ascending key order.
+assocs :: (Enum a, Unbox b) => DAWG a b c -> [([a], c)]
+assocs d = map (first (map toEnum)) (subPairs (rootID d) d)
+{-# SPECIALIZE assocs :: Unbox b => DAWG Char b c -> [(String, c)] #-}
+
+
 -- | Return all keys of the DAWG in ascending order.
-keys :: (Enum a, Trans t, Unbox b) => DAWG t a b c -> [[a]]
+keys :: (Enum a, Unbox b) => DAWG a b c -> [[a]]
 keys = map fst . assocs
-{-# SPECIALIZE keys :: (Trans t, Unbox b) => DAWG t Char b c -> [String] #-}
+{-# SPECIALIZE keys :: Unbox b => DAWG Char b c -> [String] #-}
 
+
 -- | Return all elements of the DAWG in the ascending order of their keys.
-elems :: (Trans t, Unbox b) => DAWG t a b c -> [c]
-elems = map snd . assocs'I 0
+elems :: Unbox b => DAWG a b c -> [c]
+elems d = map snd $ subPairs (rootID d) d
 
+
 -- | Construct 'DAWG' from the list of (word, value) pairs.
 -- First a 'D.DAWG' is created and then it is frozen using
 -- the 'freeze' function.
-fromList
-    :: (Enum a, D.MkNode t b)
-    => [([a], b)] -> DAWG t a () b
+fromList :: (Enum a, Ord b) => [([a], b)] -> DAWG a () b
 fromList = freeze . D.fromList
-{-# SPECIALIZE fromList
-        :: D.MkNode t b => [(String, b)] -> DAWG t Char () b #-}
+{-# SPECIALIZE fromList :: Ord b => [(String, b)] -> DAWG Char () b #-}
 
+
 -- | Construct DAWG from the list of (word, value) pairs
 -- with a combining function.  The combining function is
 -- applied strictly. First a 'D.DAWG' is created and then
 -- it is frozen using the 'freeze' function.
-fromListWith
-    :: (Enum a, D.MkNode t b)
-    => (b -> b -> b) -> [([a], b)] -> DAWG t a () b
+fromListWith :: (Enum a, Ord b) => (b -> b -> b) -> [([a], b)] -> DAWG a () b
 fromListWith f = freeze . D.fromListWith f
 {-# SPECIALIZE fromListWith
-        :: D.MkNode t b => (b -> b -> b)
-        -> [(String, b)] -> DAWG t Char () b #-}
+        :: Ord b => (b -> b -> b)
+        -> [(String, b)] -> DAWG Char () b #-}
 
+
 -- | Make DAWG from the list of words.  Annotate each word with
 -- the @()@ value.  First a 'D.DAWG' is created and then it is frozen
 -- using the 'freeze' function.
-fromLang 
-    :: (Enum a, D.MkNode t ())
-    => [[a]] -> DAWG t a () ()
+fromLang :: Enum a => [[a]] -> DAWG a () ()
 fromLang = freeze . D.fromLang
-{-# SPECIALIZE fromLang :: D.MkNode t () => [String] -> DAWG t Char () () #-}
+{-# SPECIALIZE fromLang :: [String] -> DAWG Char () () #-}
 
+
 -- | Weight of a node corresponds to the number of final states
 -- reachable from the node.  Weight of an edge is a sum of weights
 -- of preceding nodes outgoing from the same parent node.
 type Weight = Int
 
+
 -- | Compute node weights and store corresponding values in transition labels.
-weigh :: Trans t => DAWG t a b c -> DAWG t a Weight c
-weigh d = (DAWG . V.fromList)
+-- Be aware, that the entire DAWG will be weighted, even when (because of the use of
+-- the `submap` function) only a part of the DAWG is currently selected.
+weigh :: DAWG a b c -> DAWG a Weight c
+weigh d = flip DAWG (rootID d) $ V.fromList
     [ branch n ws
     | i <- [0 .. numStates d - 1]
     , let n  = nodeBy i d
@@ -207,13 +268,14 @@
     -- Plain children and epsilon child. 
     allChildren n = N.eps n : N.children n
 
+
 -- | Construct immutable version of the automaton.
-freeze :: Trans t => D.DAWG t a b -> DAWG t a () b
-freeze d = DAWG . V.fromList $
-    map (N.reID newID . oldBy)
+freeze :: D.DAWG a b -> DAWG a () b
+freeze d = flip DAWG 0 . V.fromList $
+    map (N.fromDyn newID . oldBy)
         (M.elems (inverse old2new))
   where
-    -- Map from old to new identifiers.
+    -- Map from old to new identifiers.  The root identifier is mapped to 0.
     old2new = M.fromList $ (D.root d, 0) : zip (nodeIDs d) [1..]
     newID   = (M.!) old2new
     -- List of node IDs without the root ID.
@@ -221,12 +283,14 @@
     -- Non-frozen node by given identifier.
     oldBy i = G.nodeBy i (D.graph d)
         
+
 -- | Inverse of the map.
 inverse :: M.IntMap Int -> M.IntMap Int
 inverse =
     let swap (x, y) = (y, x)
     in  M.fromList . map swap . M.toList
 
+
 -- -- | Yield mutable version of the automaton.
 -- thaw :: (Unbox b, Ord a) => DAWG a b c -> D.DAWG a b
 -- thaw d =
@@ -242,7 +306,7 @@
 --     -- New identifiers for value nodes.
 --     valIDs = foldl' updID GM.empty (values d)
 --     -- Values in the automaton.
---     values = map value . V.toList . unDAWG
+--     values = map value . V.toList . nodes
 --     -- Update ID map.
 --     updID m v = case GM.lookup v m of
 --         Just i  -> m
@@ -250,14 +314,38 @@
 --             let j = GM.size m + n
 --             in  j `seq` GM.insert v j
 
+
+-- | A number of distinct (key, value) pairs in the weighted DAWG.
+size :: DAWG a Weight c -> Int
+size d = size'I (rootID d) d
+
+
+size'I :: ID -> DAWG a Weight c -> Int
+size'I i d = add $ do
+    x <- case N.edges n of
+        [] -> Nothing
+        xs -> Just (fst $ last xs)
+    (j, v) <- N.onSym' x n
+    return $ v + size'I j d
+  where
+    n = nodeBy i d
+    u = maybe 0 (const 1) (leafValue n d)
+    add m = u + maybe 0 id m
+
+
+-----------------------------------------
+-- Index
+-----------------------------------------
+
+
 -- | Position in a set of all dictionary entries with respect
 -- to the lexicographic order.
-index :: (Enum a, Trans t) => [a] -> DAWG t a Weight c -> Maybe Int
-index xs = index'I (map fromEnum xs) 0
-{-# SPECIALIZE index
-        :: Trans t => String -> DAWG t Char Weight c -> Maybe Int #-}
+index :: Enum a => [a] -> DAWG a Weight c -> Maybe Int
+index xs d = index'I (map fromEnum xs) (rootID d) d
+{-# SPECIALIZE index :: String -> DAWG Char Weight c -> Maybe Int #-}
 
-index'I :: Trans t => [Sym] -> ID -> DAWG t a Weight c -> Maybe Int
+
+index'I :: [Sym] -> ID -> DAWG a Weight c -> Maybe Int
 index'I []     i d = 0 <$ leafValue (nodeBy i d) d
 index'I (x:xs) i d = do
     let n = nodeBy i d
@@ -266,20 +354,15 @@
     w <- index'I xs j d
     return (u + v + w)
 
--- | Perfect hashing function for dictionary entries.
--- A synonym for the 'index' function.
-hash :: (Enum a, Trans t) => [a] -> DAWG t a Weight c -> Maybe Int
-hash = index
-{-# INLINE hash #-}
 
 -- | Find dictionary entry given its index with respect to the
 -- lexicographic order.
-byIndex :: (Enum a, Trans t) => Int -> DAWG t a Weight c -> Maybe [a]
-byIndex ix d = map toEnum <$> byIndex'I ix 0 d
-{-# SPECIALIZE byIndex
-        :: Trans t => Int -> DAWG t Char Weight c -> Maybe String #-}
+byIndex :: Enum a => Int -> DAWG a Weight c -> Maybe [a]
+byIndex ix d = map toEnum <$> byIndex'I ix (rootID d) d
+{-# SPECIALIZE byIndex :: Int -> DAWG Char Weight c -> Maybe String #-}
 
-byIndex'I :: Trans t => Int -> ID -> DAWG t a Weight c -> Maybe [Sym]
+
+byIndex'I :: Int -> ID -> DAWG a Weight c -> Maybe [Sym]
 byIndex'I ix i d
     | ix < 0    = Nothing
     | otherwise = here <|> there
@@ -295,8 +378,3 @@
         xs <- byIndex'I (ix - u - w) j d
         return (x:xs)
     cmp w = compare w (ix - u)
-
--- | Inverse of the 'hash' function and a synonym for the 'byIndex' function.
-unHash :: (Enum a, Trans t) => Int -> DAWG t a Weight c -> Maybe [a]
-unHash = byIndex
-{-# INLINE unHash #-}
diff --git a/src/Data/DAWG/Static/Node.hs b/src/Data/DAWG/Static/Node.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DAWG/Static/Node.hs
@@ -0,0 +1,98 @@
+{-# LANGUAGE RecordWildCards #-}
+
+-- | Internal representation of a static automata node.
+
+module Data.DAWG.Static.Node
+( Node(..)
+, onSym
+, onSym'
+, edges
+, children
+, insert
+, fromDyn
+) where
+
+import Control.Arrow (second)
+import Control.Applicative ((<$>), (<*>))
+import Data.Binary (Binary, Get, put, get)
+import Data.Vector.Binary ()
+import qualified Data.Vector.Unboxed as U
+
+import Data.DAWG.Types
+import Data.DAWG.Trans.Vector (Trans)
+import qualified Data.DAWG.Trans as T
+import qualified Data.DAWG.Dynamic.Node as D
+
+-- | 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.
+--
+-- Since 'Leaf' nodes are distinguished from 'Branch' nodes, two values
+-- equal with respect to '==' function are always kept in one 'Leaf'
+-- node in the graph.  It doesn't change the fact that to all 'Branch'
+-- nodes one value is assigned through the epsilon transition.
+--
+-- Invariant: the 'eps' identifier always points to the 'Leaf' node.
+-- Edges in the 'edgeMap', on the other hand, point to 'Branch' nodes.
+data Node a b
+    = Branch {
+        -- | Epsilon transition.
+          eps       :: {-# UNPACK #-} !ID
+        -- | Transition map (outgoing edges).
+        , transMap  :: !Trans
+        -- | Labels corresponding to individual edges.
+        , labelVect :: !(U.Vector a) }
+    | Leaf { value  :: !(Maybe b) }
+    deriving (Show, Eq, Ord)
+
+instance (U.Unbox a, Binary a, Binary b) => Binary (Node a b) where
+    put Branch{..} = put (1 :: Int) >> put eps >> put transMap >> put labelVect
+    put Leaf{..}   = put (2 :: Int) >> put value
+    get = do
+        x <- get :: Get Int
+        case x of
+            1 -> Branch <$> get <*> get <*> get
+            _ -> Leaf <$> get
+
+-- | Transition function.
+onSym :: Sym -> Node a b -> Maybe ID
+onSym x (Branch _ t _)  = T.lookup x t
+onSym _ (Leaf _)        = Nothing
+{-# INLINE onSym #-}
+
+-- | Transition function.
+onSym' :: U.Unbox a => Sym -> Node a b -> Maybe (ID, a)
+onSym' x (Branch _ t ls)   = do
+    k <- T.index x t
+    (,) <$> (snd <$> T.byIndex k t)
+        <*> ls U.!? k
+onSym' _ (Leaf _)           = Nothing
+{-# INLINE onSym' #-}
+
+-- | List of symbol/edge pairs outgoing from the node.
+edges :: Node a b -> [(Sym, ID)]
+edges (Branch _ t _)    = T.toList t
+edges (Leaf _)          = []
+{-# INLINE edges #-}
+
+-- | List of children identifiers.
+children :: Node a b -> [ID]
+children = map snd . edges
+{-# INLINE children #-}
+
+-- | Substitue edge determined by a given symbol.
+insert :: Sym -> ID -> Node a b -> Node a b
+insert x i (Branch w t ls)  = Branch w (T.insert x i t) ls
+insert _ _ l                = l
+{-# INLINE insert #-}
+
+-- | Make "static" node from a "dynamic" node.
+fromDyn
+    :: (ID -> ID)   -- ^ Assign new IDs 
+    -> D.Node b     -- ^ "Dynamic" node
+    -> Node () b    -- ^ "Static" node
+fromDyn _ (D.Leaf x)        = Leaf x
+fromDyn f (D.Branch e t)    =
+    let reTrans = T.fromList . map (second f) . T.toList
+    in  Branch (f e) (reTrans t) U.empty
