diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -12,10 +12,23 @@
 ## salak-toml
 [![salak-toml](https://img.shields.io/hackage/v/salak-toml.svg)](https://hackage.haskell.org/package/salak-toml)
 
-This library define a universal procedure to load configurations and parse properties, also supports reload configuration files.
+## Introduction
+This library defines a universal procedure to load configurations and parse properties, also supports reload configuration files.
 
-We can load configurations from command line, environment, configuration files such as yaml or toml etc, and we may want to have our own strategies to load configurations from multi sources and overwrite properties by orders of these sources.
+## Parse Functions
 
+`HasSalak` monad provide a unified function `require` to parse properties. Here are some examples.
+
+```Haskell
+a :: Bool              <- require "bool.key"
+b :: Maybe Int         <- require "int.optional.key"
+c :: Either String Int <- require "int.error.key"
+d :: IO Int            <- require "int.reloadable.key" -- This property can be changed by reloading configurations.
+```
+
+## Load Strategy
+We can load configurations from command lines, environment, configuration files such as yaml or toml etc., and we may want to have our own strategies to load configurations from multiply sources and overwrite properties by orders of these sources.
+
 `PropConfig` defines a common loading strategy:
 > 1. loadCommandLine
 > 2. loadEnvironment
@@ -25,26 +38,15 @@
 > 6. load file from home folder if enabled
 > 7. file extension matching, support yaml or toml or any other loader.
 
-Load earlier has higher orders, orders cannot be changed.
-
-`ReaderT SourcePack m` defines how to read properties:
-```Haskell
-require "abc.prop"
-```
-
-`ReloadableSourcePackT m` defines how to read reloadable properties:
-```Haskell
-requireD "abc.dynamic.prop"
-```
+Load earlier has higher priorities. Priorities cannot be changed.
 
-For commandline and environment, 
+For command lines and environment, 
 ```
 CommandLine:  --package.a.enabled=true
 Environment: PACKAGE_A_ENABLED: false
 ```
 
-Usage:
-
+## Usage
 
 Environment:
 ```
@@ -69,7 +71,7 @@
   , ext  :: Int
   } deriving (Eq, Show)
 
-instance MonadCatch m => FromProp m Config where
+instance Monad m => FromProp m Config where
   fromProp = Config
     <$> "user" ? pattern "[a-z]{5,16}"
     <*> "pwd"
@@ -77,17 +79,17 @@
 
 main = runSalakWith "salak" (YAML :|: TOML) $ do
   c :: Config <- require "test.config"
-  lift $ print c=
+  lift $ print c
 ```
 
 GHCi play
 ```Haskell
-λ> :set -XFlexibleInstances -XMultiParamTypeClasses 
+λ> :set -XFlexibleInstances -XMultiParamTypeClasses -XOverloadedStrings
 λ> import Salak
 λ> import Data.Default
 λ> import Data.Text(Text)
 λ> data Config = Config { name :: Text, dir  :: Maybe Text, ext  :: Int} deriving (Eq, Show)
-λ> instance MonadCatch m => FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1
+λ> instance Monad m => FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1
 λ> runSalak def (require "") :: IO Config
 Config {name = "daniel", dir = Nothing, ext = 1}
 ```
diff --git a/salak.cabal b/salak.cabal
--- a/salak.cabal
+++ b/salak.cabal
@@ -1,13 +1,13 @@
 cabal-version: 1.12
 name: salak
-version: 0.3
+version: 0.3.1
 license: BSD3
 license-file: LICENSE
 copyright: (c) 2018 Daniel YU
 maintainer: Daniel YU <leptonyu@gmail.com>
 author: Daniel YU
 homepage: https://github.com/leptonyu/salak#readme
-synopsis: Configuration Loader
+synopsis: Configuration (re)Loader and Parser.
 category: Library, Configuration
 build-type: Simple
 extra-source-files:
diff --git a/src/Salak.hs b/src/Salak.hs
--- a/src/Salak.hs
+++ b/src/Salak.hs
@@ -7,13 +7,13 @@
 {-# LANGUAGE TypeOperators       #-}
 -- |
 -- Module:      Salak
--- Copyright:   (c) 2019 Daniel YU
+-- Copyright:   2019 Daniel YU
 -- License:     BSD3
 -- Maintainer:  leptonyu@gmail.com
 -- Stability:   experimental
 -- Portability: portable
 --
--- Configuration Loader for Production in Haskell.
+-- Configuration (re)Loader and Parser.
 --
 module Salak(
   -- * How to use this library
@@ -25,11 +25,18 @@
   , loadAndRunSalak
   , loadAndRunSalak'
   , PropConfig(..)
-  -- * Run Functions
-  , HasSalak(..)
+  -- * Parsing Properties Function
   , MonadSalak(..)
   , RunSalakT
   , RunSalak
+  -- ** Operators
+  , PropOp(..)
+  , FromProp(..)
+  , Prop
+  , readPrimitive
+  , readEnum
+  , SourcePack
+  , SalakException(..)
   -- * Load Functions
   -- ** Monad for Loader
   , LoadSalakT
@@ -49,15 +56,6 @@
   , (:|:)(..)
   -- ** Reload Functions
   , ReloadResult(..)
-  , askReload
-  -- * Properties Parsers
-  , PropOp(..)
-  , FromProp(..)
-  , Prop
-  , readPrimitive
-  , readEnum
-  , SourcePack
-  , PropException(..)
   -- * Reexport
   , MonadCatch
   , MonadThrow
@@ -128,7 +126,7 @@
 -- > 6. load file from home folder if enabled
 -- > 7. file extension matching, support yaml or toml or any other loader.
 --
-loadSalak :: (MonadCatch m, MonadIO m) => PropConfig -> LoadSalakT m ()
+loadSalak :: (MonadThrow m, MonadIO m) => PropConfig -> LoadSalakT m ()
 loadSalak PropConfig{..} = do
   loadCommandLine commandLine
   loadEnv
@@ -143,12 +141,12 @@
     ifS _    _   = return Nothing
     loadConf n mf = lift mf >>= mapM_ (liftNT . loadExt . (</> n))
 
-loadSalakWith :: (MonadCatch m, MonadIO m, HasLoad file) => file -> FileName -> LoadSalakT m ()
+loadSalakWith :: (MonadThrow m, MonadIO m, HasLoad file) => file -> FileName -> LoadSalakT m ()
 loadSalakWith file name = loadSalak def { configName = Just name, loadExt = loadByExt file }
 
 -- | Standard salak functions, by load and run with `RunSalakT`.
 loadAndRunSalak :: (MonadThrow m, MonadIO m) => LoadSalakT m () -> RunSalakT m a -> m a
-loadAndRunSalak lstm ma = loadAndRunSalak' lstm $ \sp -> runRunSalak sp ma
+loadAndRunSalak lstm ma = loadAndRunSalak' lstm $ runRun ma
 
 -- | Run salak, load strategy refer to `loadSalak`
 runSalak :: (MonadCatch m, MonadIO m) => PropConfig -> RunSalakT m a -> m a
@@ -160,10 +158,11 @@
 
 -- $use
 --
--- | This library define a universal procedure to load configurations and parse properties, also supports reload configuration files.
+-- | This library defines a universal procedure to load configurations and parse properties, also supports reload configurations.
 --
 --
--- We can load configurations from command line, environment, configuration files such as yaml or toml etc, and we may want to have our own strategies to load configurations from multi sources and overwrite properties by orders of these sources.
+-- We can load configurations from command lines, environment, configuration files such as yaml or toml etc.,
+-- and we may want to have our own strategies to load configurations from multiply sources and overwrite properties by orders of these sources.
 --
 -- `PropConfig` defines a common loading strategy:
 --
@@ -175,51 +174,26 @@
 -- > 6. load file from home folder if enabled
 -- > 7. file extension matching, support yaml or toml or any other loader.
 --
--- Load earlier has higher priority, priorities cannot be changed.
---
---
--- Usage:
---
---
--- Environment:
---
--- > export TEST_CONFIG_NAME=daniel
---
--- Current Directory:  salak.yaml
---
--- > test.config:
--- >   name: noop
--- >   dir: ls
+-- Load earlier has higher priority. Priorities cannot be changed.
 --
--- Current Directory:  salak.toml
+-- After loading configurations, we can use `require` to parse properties. For example:
 --
--- > [test.config]
--- > ext=2
+-- > a :: Bool              <- require "bool.key"
+-- > b :: Maybe Int         <- require "int.optional.key"
+-- > c :: Either String Int <- require "int.error.key"
+-- > d :: IO Int            <- require "int.reloadable.key"
 --
--- > data Config = Config
--- >   { name :: Text
--- >   , dir  :: Maybe Text
--- >   , ext  :: Int
--- >   } deriving (Eq, Show)
--- >
--- > instance MonadCatch m => FromProp m Config where
--- >   fromProp = Config
--- >     <$> "user" ? pattern "[a-z]{5,16}"
--- >     <*> "pwd"
--- >     <*> "ext" .?= 1
--- >
--- > main = runSalakWith "salak" (YAML :|: TOML) $ do
--- >   c :: Config <- require "test.config"
--- >   lift $ print c
+-- Salak supports parse `IO` values, which actually wrap a 'Control.Concurrent.MVar.MVar' variable and can be reseted by reloading configurations.
+-- Normal value will not be affected by reloading configurations.
 --
 -- GHCi play
 --
--- > λ> :set -XFlexibleInstances -XMultiParamTypeClasses
--- > λ> import Salak
--- > λ> import Data.Default
--- > λ> import Data.Text(Text)
--- > λ> data Config = Config { name :: Text, dir  :: Maybe Text, ext  :: Int} deriving (Eq, Show)
--- > λ> instance MonadCatch m => FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1
--- > λ> runSalak def (require "") :: IO Config
--- > Config {name = "daniel", dir = Nothing, ext = 1}
+-- >>> :set -XFlexibleInstances -XMultiParamTypeClasses -XOverloadedStrings
+-- >>> import Salak
+-- >>> import Data.Default
+-- >>> import Data.Text(Text)
+-- >>> data Config = Config { name :: Text, dir  :: Maybe Text, ext  :: Int} deriving (Eq, Show)
+-- >>> instance Monad m => FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1
+-- >>> runSalak def (require "") :: IO Config
+-- Config {name = "daniel", dir = Nothing, ext = 1}
 --
diff --git a/src/Salak/Internal.hs b/src/Salak/Internal.hs
--- a/src/Salak/Internal.hs
+++ b/src/Salak/Internal.hs
@@ -11,6 +11,16 @@
 {-# LANGUAGE TupleSections              #-}
 {-# LANGUAGE TypeFamilies               #-}
 {-# LANGUAGE UndecidableInstances       #-}
+-- |
+-- Module:      Salak.Internal
+-- Copyright:   2019 Daniel YU
+-- License:     BSD3
+-- Maintainer:  leptonyu@gmail.com
+-- Stability:   experimental
+-- Portability: portable
+--
+-- This module is used for implementing loaders.
+--
 module Salak.Internal(
     loadAndRunSalak'
   , loadTrie
@@ -19,8 +29,7 @@
   , LoadSalak
   , RunSalakT
   , RunSalak
-  , runRunSalak
-  , HasSalak(..)
+  , runRun
   , MonadSalak(..)
   , loadMock
   , loadEnv
@@ -47,6 +56,7 @@
 import           Control.Concurrent.MVar
 import           Control.Monad
 import           Control.Monad.Catch
+import           Control.Monad.Except
 import           Control.Monad.IO.Class  (MonadIO, liftIO)
 import qualified Control.Monad.IO.Unlift as IU
 import           Control.Monad.Reader
@@ -74,77 +84,46 @@
   }
 
 -- | Configuration Loader Monad, used for load properties from sources. Custom loaders using `loadTrie`
-newtype LoadSalakT  m a = LoadSalakT  { unLoad  :: MS.StateT UpdateSource m a } deriving (Functor, Applicative, Monad, MS.MonadTrans)
+newtype LoadSalakT  m a = LoadSalakT (MS.StateT UpdateSource m a)
+  deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MS.MonadState UpdateSource, MonadThrow, MonadCatch)
 
 -- | Simple IO Monad
 type LoadSalak = LoadSalakT IO
 
+runLoad :: Monad m => LoadSalakT m a -> UpdateSource -> m a
+runLoad (LoadSalakT ma) us = MS.evalStateT ma us
+
 liftNT :: MonadIO m => LoadSalak () -> LoadSalakT m ()
-liftNT (LoadSalakT a) = do
-  ud <- MS.get
-  MS.liftIO $ MS.evalStateT a ud
+liftNT a = MS.get >>= liftIO . runLoad a
 
 instance MonadIO m => MonadSalak (LoadSalakT m) where
   askSalak = MS.get >>= toSourcePack
 
-instance MonadThrow m => MonadThrow (LoadSalakT m) where
-  throwM = LoadSalakT . throwM
-
-instance MonadCatch m => MonadCatch (LoadSalakT m) where
-  catch m f = do
-    us <- MS.get
-    lift $ MS.evalStateT (unLoad m) us `catch` (\e -> MS.evalStateT (unLoad $ f e) us)
-
-instance Monad m => MS.MonadState UpdateSource (LoadSalakT m) where
-  state f = LoadSalakT $ MS.state f
-
-instance MonadIO m => MonadIO (LoadSalakT m) where
-  liftIO = LoadSalakT . liftIO
-
-instance IU.MonadUnliftIO m => IU.MonadUnliftIO (LoadSalakT m) where
-  askUnliftIO = LoadSalakT $ do
+instance (MonadThrow m, IU.MonadUnliftIO m) => IU.MonadUnliftIO (LoadSalakT m) where
+  askUnliftIO = do
     ut <- MS.get
-    f  <- MS.lift IU.askUnliftIO
-    return $ IU.UnliftIO $ IU.unliftIO f . (`MS.evalStateT` ut) . unLoad
+    lift $ IU.withUnliftIO $ \u -> return (IU.UnliftIO (IU.unliftIO u . flip runLoad ut))
 
--- | Standard `HasSalak` instance.
-newtype RunSalakT m a = RunSalakT { unRun :: ReaderT SourcePack m a } deriving (Functor, Applicative, Monad, MonadTrans)
+-- | Standard `MonadSalak` instance.
+newtype RunSalakT m a = RunSalakT (ReaderT SourcePack m a)
+  deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MonadReader SourcePack, MonadThrow, MonadCatch)
 
 -- | Simple IO Monad
 type RunSalak = RunSalakT IO
 
+runRun :: Monad m => RunSalakT m a -> SourcePack -> m a
+runRun (RunSalakT ma) us = runReaderT ma us
+
 instance Monad m => MonadSalak (RunSalakT m) where
   askSalak = RunSalakT ask
 
-instance Monad m => MonadReader SourcePack (RunSalakT m)  where
-  ask = RunSalakT ask
-  local f m = RunSalakT $ local f $ unRun m
-
-instance MonadThrow m => MonadThrow (RunSalakT m) where
-  throwM = RunSalakT . throwM
-
-instance MonadCatch m => MonadCatch (RunSalakT m) where
-  catch m f = do
-    us <- ask
-    lift $ runReaderT (unRun m) us `catch` (\e -> runReaderT (unRun $ f e) us)
-
-instance MonadIO m => MonadIO (RunSalakT m) where
-  liftIO = RunSalakT . liftIO
-
-instance IU.MonadUnliftIO m => IU.MonadUnliftIO (RunSalakT m) where
-  askUnliftIO = RunSalakT $ do
+instance (MonadThrow m, IU.MonadUnliftIO m) => IU.MonadUnliftIO (RunSalakT m) where
+  askUnliftIO = do
     ut <- ask
-    f  <- lift IU.askUnliftIO
-    return $ IU.UnliftIO $ IU.unliftIO f . (`runReaderT` ut) . unRun
-
-instance {-# OVERLAPPABLE #-} (m' ~ t (RunSalakT m), MonadTrans t, Monad m, Monad m') => MonadSalak m' where
-  askSalak = lift askSalak
-
-runRunSalak :: SourcePack -> RunSalakT m a -> m a
-runRunSalak sp (RunSalakT m) = runReaderT m sp
+    lift $ IU.withUnliftIO $ \u -> return (IU.UnliftIO (IU.unliftIO u . flip runRun ut))
 
 -- | Basic loader
-loadTrie :: MonadIO m => Bool -> String -> (Int -> IO TraceSource) -> LoadSalakT m ()
+loadTrie :: (MonadThrow m, MonadIO m) => Bool -> String -> (Int -> IO TraceSource) -> LoadSalakT m ()
 loadTrie canReload name f = do
   UpdateSource{..} <- MS.get
   v              <- liftIO $ readMVar ref
@@ -156,7 +135,7 @@
       let nut = UpdateSource ref (refNo + 1) (HM.insert refNo name refMap) qfunc update
       _ <- liftIO $ swapMVar ref t
       MS.put nut
-    else error $ show es
+    else throwM $ PropException $ unlines es
   where
     go ts ud n = return $ do
       (c,d) <- ud
@@ -164,20 +143,20 @@
       return (c1,d)
 
 -- | Simple loader
-loadList :: (MonadIO m, Foldable f, ToKeys k, ToValue v) => Bool -> String -> IO (f (k,v)) -> LoadSalakT m ()
+loadList :: (MonadThrow m, MonadIO m, Foldable f, ToKeys k, ToValue v) => Bool -> String -> IO (f (k,v)) -> LoadSalakT m ()
 loadList canReload name iof = loadTrie canReload name (\i -> gen i <$> iof)
 
 -- | Standard salak functions, by load and with a `SourcePack` instance.
---  Users should use `SourcePack` to create custom `MonadSalak` instances, then you get will an instance of `HasSalak`.
+--  Users should use `SourcePack` to create custom `MonadSalak` instances, then you get will an instance of `MonadSalak`.
 loadAndRunSalak' :: (MonadThrow m, MonadIO m) => LoadSalakT m () -> (SourcePack -> m a) -> m a
 loadAndRunSalak' lstm f = load lstm >>= f
 
-load :: MonadIO m => LoadSalakT m () -> m SourcePack
-load (LoadSalakT lm) = do
+load :: (MonadThrow m, MonadIO m) => LoadSalakT m () -> m SourcePack
+load lm = do
   r <- liftIO $ newMVar T.empty
   q <- liftIO $ newMVar $ \s -> Right $ void $ swapMVar r s
   u <- liftIO $ newMVar $ return (T.empty, return ())
-  MS.execStateT lm (UpdateSource r 0 HM.empty q u) >>= toSourcePack
+  runLoad (lm >> MS.get) (UpdateSource r 0 HM.empty q u) >>= toSourcePack
 
 toSourcePack :: MonadIO m => UpdateSource -> m SourcePack
 toSourcePack UpdateSource{..} = liftIO (readMVar ref) >>= \s -> return $ SourcePack s [] qfunc go
@@ -194,11 +173,11 @@
         else return (ReloadResult True es)
 
 -- | Load mock variables into `Source`
-loadMock :: MonadIO m => [(Text, Text)] -> LoadSalakT m ()
+loadMock :: (MonadThrow m, MonadIO m) => [(Text, Text)] -> LoadSalakT m ()
 loadMock fa = loadList False "mock" (return fa)
 
 -- | Load environment variables into `Source`
-loadEnv :: MonadIO m => LoadSalakT m ()
+loadEnv :: (MonadThrow m, MonadIO m) => LoadSalakT m ()
 loadEnv = loadList False "environment" go
   where
     go = concatMap split2 . filter ((/= '_') . head . fst) <$> getEnvironment
@@ -218,7 +197,7 @@
     go _ = Nothing
 
 -- | Default way to parse command line arguments
-loadCommandLine :: MonadIO m => ParseCommandLine -> LoadSalakT m ()
+loadCommandLine :: (MonadThrow m, MonadIO m) => ParseCommandLine -> LoadSalakT m ()
 loadCommandLine pcl = loadList False "commandLine" (getArgs >>= pcl)
 
 -- | Try load file, if file does not exist then do nothing.
diff --git a/src/Salak/Internal/Prop.hs b/src/Salak/Internal/Prop.hs
--- a/src/Salak/Internal/Prop.hs
+++ b/src/Salak/Internal/Prop.hs
@@ -26,6 +26,7 @@
 import qualified Data.HashMap.Strict     as HM
 import           Data.Int
 import           Data.List               (sortBy)
+import           Data.Maybe
 import           Data.Menshen
 import           Data.Scientific
 import           Data.Semigroup
@@ -51,10 +52,13 @@
   fromProp = fmap to gFromProp
 
 newtype Prop m a
-  = Prop { unProp :: ReaderT SourcePack m a }
-  deriving (Functor, Applicative, Monad, MonadReader SourcePack, MonadTrans)
+  = Prop { unProp :: ReaderT SourcePack (ExceptT SomeException m) a }
+  deriving (Functor, Applicative, Monad, MonadReader SourcePack, MonadIO)
 
-instance MonadCatch m => A.Alternative (Prop m) where
+instance MonadTrans Prop where
+  lift = Prop . lift . lift
+
+instance Monad m => A.Alternative (Prop m) where
   empty = notFound
   a <|> b = do
     v <- try a
@@ -63,40 +67,67 @@
       Left (_ :: SomeException) -> b
 
 -- | Core type class of salak, which provide function to parse properties.
-class HasSalak m where
+class Monad m => MonadSalak m where
+  -- | Monad has the ability to get a `SourcePack` instance.
+  askSalak :: m SourcePack
+
+  -- | Get reload action which used for reload profiles
+  askReload :: MonadSalak m => m (IO ReloadResult)
+  askReload = reload <$> askSalak
+
   -- | Parse properties using `FromProp`. For example:
   --
   -- > a :: Bool              <- require "bool.key"
   -- > b :: Maybe Int         <- require "int.optional.key"
   -- > c :: Either String Int <- require "int.error.key"
   -- > d :: IO Int            <- require "int.reloadable.key"
-  require :: FromProp m a => Text -> m a
-
-instance (MonadThrow m, MonadSalak m) => HasSalak m where
+  --
+  -- `require` supports parse `IO` values, which actually wrap a 'MVar' variable and can be reseted by reloading configurations.
+  -- Normal value will not be affected by reloading configurations.
+  require :: (MonadThrow m, FromProp m a) => Text -> m a
   require ks = do
     sp@SourcePack{..} <- askSalak
     case search ks source of
       Left  e     -> throwM $ PropException e
-      Right (k,t) -> runProp sp { source = t, pref = pref ++ unKeys k} fromProp
+      Right (k,t) -> runProp1 sp { source = t, pref = pref ++ unKeys k} fromProp
 
+instance {-# OVERLAPPABLE #-} (m ~ t m', Monad m', Monad m, MonadTrans t, MonadSalak m') => MonadSalak m where
+  askSalak = lift askSalak
+
 instance Monad m => MonadSalak (Prop m) where
   askSalak = Prop ask
 
-instance MonadIO m => MonadIO (Prop m) where
-  liftIO = Prop . liftIO
-
-instance MonadThrow m => MonadThrow (Prop m) where
-  throwM = Prop . throwM
+instance Monad m => MonadThrow (Prop m) where
+  throwM = Prop . lift . throwError . toException
 
-instance MonadCatch m => MonadCatch (Prop m) where
-  catch (Prop a) f = Prop $ do
+instance Monad m => MonadCatch (Prop m) where
+  catch (Prop a) f = do
     sp <- ask
-    lift $ runReaderT a sp `catch` (\e -> runReaderT (unProp $ f e) sp)
+    v  <- lift $ runExceptT (runReaderT a sp)
+    case v of
+      Left  e -> case fromException e of
+        Just ee -> f ee
+        _       -> throwM e
+      Right x -> return x
 
-runProp :: Monad m => SourcePack -> Prop m a ->  m a
-runProp sp (Prop p) = runReaderT p sp
+runProp2 :: Monad m => SourcePack -> Prop m a -> m (Either SomeException a)
+runProp2 sp (Prop p) = runExceptT (runReaderT p sp)
 
-instance (MonadCatch m, FromProp m a) => FromProp m (Maybe a) where
+runProp1 :: MonadThrow m => SourcePack -> Prop m a -> m a
+runProp1 sp p = do
+  v <- runProp2 sp p
+  case v of
+    Left  e -> throwM e
+    Right x -> return x
+
+runProp :: Monad m => SourcePack -> Prop m a -> Prop m a
+runProp sp p = do
+  v <- lift $ runProp2 sp p
+  case v of
+    Left  e -> throwM e
+    Right x -> return x
+
+instance FromProp m a => FromProp m (Maybe a) where
   fromProp = do
     v <- try fromProp
     case v of
@@ -105,70 +136,73 @@
         _                  -> throwM e
       Right a -> return (Just a)
 
-instance (MonadCatch m, FromProp m a) => FromProp m (Either String a) where
+instance FromProp m a => FromProp m (Either String a) where
   fromProp = do
-    sp@SourcePack{..} <- askSalak
-    lift $ convertExp (Left $ show (Keys pref) ++ " is null") <$> try (runProp sp fromProp)
+    SourcePack{..} <- ask
+    v <- try fromProp
+    return $ case v of
+      Left  e -> case fromException e of
+        Just (PropException x) -> Left x
+        Just NullException     -> Left $ show (Keys pref) ++ " is null"
+        _                      -> Left $ show e
+      Right a -> Right a
 
 instance {-# OVERLAPPABLE #-} FromProp m a => FromProp m [a] where
   fromProp = do
     sp@SourcePack{..} <- askSalak
-    let TR.Trie _ m = source
-    lift $ foldM (go sp) [] $ sortBy g2 $ filter (isNum.fst) $ HM.toList m
+    foldM (go sp) [] $ sortBy g2 $ filter (isNum.fst) $ HM.toList $ TR.getMap source
     where
       go s vs (k,t) = (:vs) <$> runProp s { pref = pref s ++ [k], source = t} fromProp
       g2 (a,_) (b,_) = compare b a
 
-instance {-# OVERLAPPABLE #-} (Show a, MonadThrow m, MonadIO m, FromProp (Either SomeException) a) => FromProp m (IO a) where
-  fromProp = Prop $ do
-    sp   <- ask
-    either throwM (buildIO sp) $ runProp sp (fromProp :: Prop (Either SomeException) a)
-
+-- | Supports for parsing `IO` value.
+instance {-# OVERLAPPABLE #-} (MonadIO m, MonadIO n, FromProp (Either SomeException) a, FromProp m a) => FromProp m (n a) where
+  fromProp = do
+    sp <- ask
+    a  <- fromProp
+    lift $ liftIO <$> buildIO sp a
 
-buildIO :: (Show a, MonadIO m, FromProp (Either SomeException) a) => SourcePack -> a -> m (IO a)
+buildIO :: (MonadIO m, FromProp (Either SomeException) a) => SourcePack -> a -> m (IO a)
 buildIO sp a = liftIO $ do
   aref <- newMVar a
-  modifyMVar_ (qref sp) $ \f -> return $ \s -> do
-    b  <- convertExp (Right a) $ runProp sp {source = search2 s (pref sp), pref = pref sp} fromProp
-    io <- f s
-    return (swapMVar aref b >> io)
+  modifyMVar_ (qref sp) $ \f -> return $ \s ->
+    let b = runProp1 sp {source = search2 s (pref sp), pref = pref sp} fromProp
+    in case b of
+      Left  e -> Left $ show e
+      Right v -> do
+        vb <- v
+        io <- f s
+        return (swapMVar aref (fromMaybe a vb) >> io)
   return (readMVar aref)
 
-convertExp :: Either String a -> Either SomeException a -> Either String a
-convertExp a = either readExp Right
-  where
-    readExp e = case fromException e of
-      Just (PropException x) -> Left x
-      Just NullException     -> a
-      _                      -> Left $ show e
-
-data PropException
+data SalakException
   = PropException String -- ^ Parse failed
   | NullException        -- ^ Not found
   deriving Show
 
-instance Exception PropException
+instance Exception SalakException
 
-instance (MonadThrow m, FromProp m a) => IsString (Prop m a) where
+-- | Automatic convert literal string into an instance of `Prop` @m@ @a@.
+instance FromProp m a => IsString (Prop m a) where
   fromString ks = do
     sp@SourcePack{..} <- askSalak
-    lift $ case search ks source of
+    case search ks source of
       Left  e     -> throwM $ PropException e
       Right (k,t) -> runProp sp { source = t, pref = pref ++ unKeys k} fromProp
 
-notFound :: MonadThrow m => Prop m a
+notFound :: Monad m => Prop m a
 notFound = do
   SourcePack{..} <- askSalak
   throwM NullException
 
-err :: MonadThrow m => String -> Prop m a
+err :: Monad m => String -> Prop m a
 err e = do
   SourcePack{..} <- askSalak
   throwM $ PropException $ show (Keys pref) ++ ":" ++ e
 
 -- | Prop operators.
 --
--- Suppose we have following definition:
+-- Suppose we have the following definition:
 --
 -- > data Config = Config
 -- >   { enabled :: Bool
@@ -185,7 +219,7 @@
   -- IO value will work right.
   infixl 5 .?=
   (.?=) :: f a -> a -> f a
-  -- | Parse or auto extract from a `Default` value
+  -- | Parse or auto extract default value from a `Default` value
   --
   -- > instance Default Config where
   -- >   def = Config True (return LevelInfo)
@@ -197,12 +231,12 @@
   (.?:) :: Default b => f a -> (b -> a) -> f a
   (.?:) fa b = fa .?= b def
 
--- | Support normal value
+-- | Support for setting default normal value.
 instance {-# OVERLAPPABLE #-} A.Alternative f => PropOp f a where
   (.?=) a b = a A.<|> pure b
 
--- | Support IO value
-instance (Show a, MonadCatch m, MonadIO m, FromProp (Either SomeException) a) => PropOp (Prop m) (IO a) where
+-- | Support for setting default `IO` value.
+instance (MonadIO m, FromProp (Either SomeException) a) => PropOp (Prop m) (IO a) where
   (.?=) ma a = do
     sp <- askSalak
     v  <- try ma
@@ -210,21 +244,23 @@
       Left  (_ :: SomeException) -> liftIO a >>= buildIO sp
       Right o                    -> return o
 
-instance MonadThrow m => HasValid (Prop m) where
+instance Monad m => HasValid (Prop m) where
   invalid = err . toI18n
 
 -- | Parse primitive value from `Value`
-readPrimitive :: MonadThrow m => (Value -> Either String a) -> Prop m a
+readPrimitive :: Monad m => (Value -> Either String a) -> Prop m a
 readPrimitive f = do
   SourcePack{..} <- askSalak
-  let TR.Trie v _ = source
-  case f <$> (v >>= getVal) of
+  vx <- g $ TR.getPrimitive source >>= getVal
+  case f <$> vx of
     Just (Left e)  -> err e
     Just (Right a) -> return a
     _              -> notFound
+  where
+    g = return
 
 -- | Parse enum value from `Text`
-readEnum :: MonadThrow m => (Text -> Either String a) -> Prop m a
+readEnum :: Monad m => (Text -> Either String a) -> Prop m a
 readEnum = readPrimitive . go
   where
     go f (VT t) = f t
@@ -233,13 +269,13 @@
 class Monad m => GFromProp m f where
   gFromProp :: Prop m (f a)
 
-instance {-# OVERLAPPABLE #-} (MonadThrow m, Constructor c, GFromProp m a) => GFromProp m (M1 C c a) where
+instance {-# OVERLAPPABLE #-} (Monad m, Constructor c, GFromProp m a) => GFromProp m (M1 C c a) where
     gFromProp
       | conIsRecord m = fmap M1 gFromProp
       | otherwise     = fmap M1 $ gEnum $ T.pack (conName m)
       where m = undefined :: t c a x
 
-gEnum :: (MonadThrow m, GFromProp m f) => Text -> Prop m (f a)
+gEnum :: (Monad m, GFromProp m f) => Text -> Prop m (f a)
 gEnum va = do
   o <- gFromProp
   readEnum $ \x -> if x==va then Right o else Left "enum invalid"
@@ -261,7 +297,7 @@
 instance {-# OVERLAPPABLE #-} (GFromProp m a, GFromProp m b) => GFromProp m (a:*:b) where
   gFromProp = (:*:) <$> gFromProp <*> gFromProp
 
-instance {-# OVERLAPPABLE #-} (MonadCatch m, GFromProp m a, GFromProp m b) => GFromProp m (a:+:b) where
+instance {-# OVERLAPPABLE #-} (Monad m, GFromProp m a, GFromProp m b) => GFromProp m (a:+:b) where
   gFromProp = fmap L1 gFromProp A.<|> fmap R1 gFromProp
 
 instance (Monad m, FromProp m a) => FromProp m (Identity a) where
@@ -313,10 +349,10 @@
 instance (Monad m, FromProp m a) => FromProp m (Product a) where
   fromProp = Product <$> fromProp
 
-instance (MonadCatch m, FromProp m a) => FromProp m (Option a) where
+instance (Monad m, FromProp m a) => FromProp m (Option a) where
   fromProp = Option <$> fromProp
 
-instance MonadThrow m => FromProp m Bool where
+instance Monad m => FromProp m Bool where
   fromProp = readPrimitive go
     where
       go (VB x) = Right x
@@ -328,25 +364,25 @@
         _       -> Left "string convert bool failed"
       go x      = Left $ getType x ++ " cannot be bool"
 
-instance MonadThrow m => FromProp m Text where
+instance Monad m => FromProp m Text where
   fromProp = readPrimitive go
     where
       go (VT x) = Right x
       go x      = Right $ T.pack $ snd $ typeOfV x
 
-instance MonadThrow m => FromProp m TL.Text where
+instance Monad m => FromProp m TL.Text where
   fromProp = TL.fromStrict <$> fromProp
 
-instance MonadThrow m => FromProp m B.ByteString where
+instance Monad m => FromProp m B.ByteString where
   fromProp = TB.encodeUtf8 <$> fromProp
 
-instance MonadThrow m => FromProp m BL.ByteString where
+instance Monad m => FromProp m BL.ByteString where
   fromProp = TBL.encodeUtf8 <$> fromProp
 
-instance MonadThrow m => FromProp m String where
+instance Monad m => FromProp m String where
   fromProp = T.unpack <$> fromProp
 
-instance MonadThrow m => FromProp m Scientific where
+instance Monad m => FromProp m Scientific where
   fromProp = readPrimitive go
     where
       go (VT x) = case readMaybe $ T.unpack x of
@@ -355,91 +391,91 @@
       go (VI x) = Right x
       go x      = Left $ getType x ++ " cannot be number"
 
-instance MonadThrow m => FromProp m Float where
+instance Monad m => FromProp m Float where
   fromProp = toRealFloat <$> fromProp
 
-instance MonadThrow m => FromProp m Double where
+instance Monad m => FromProp m Double where
   fromProp = toRealFloat <$> fromProp
 
-instance MonadThrow m => FromProp m Integer where
+instance Monad m => FromProp m Integer where
   fromProp = toInteger <$> (fromProp :: Prop m Int)
 
-instance MonadThrow m => FromProp m Int where
+instance Monad m => FromProp m Int where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Int8 where
+instance Monad m => FromProp m Int8 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Int16 where
+instance Monad m => FromProp m Int16 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Int32 where
+instance Monad m => FromProp m Int32 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Int64 where
+instance Monad m => FromProp m Int64 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Word where
+instance Monad m => FromProp m Word where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Word8 where
+instance Monad m => FromProp m Word8 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Word16 where
+instance Monad m => FromProp m Word16 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Word32 where
+instance Monad m => FromProp m Word32 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m Word64 where
+instance Monad m => FromProp m Word64 where
   fromProp = fromProp >>= toNum
 
-instance MonadThrow m => FromProp m NominalDiffTime where
+instance Monad m => FromProp m NominalDiffTime where
   fromProp = fromInteger <$> fromProp
 
-instance MonadThrow m => FromProp m DiffTime where
+instance Monad m => FromProp m DiffTime where
   fromProp = fromInteger <$> fromProp
 
-instance (HasResolution a, MonadThrow m) => FromProp m (Fixed a) where
+instance (HasResolution a, Monad m) => FromProp m (Fixed a) where
   fromProp = fromInteger <$> fromProp
 
-toNum :: (MonadThrow m, Integral i, Bounded i) => Scientific -> Prop m i
+toNum :: (Monad m, Integral i, Bounded i) => Scientific -> Prop m i
 toNum s = case toBoundedInteger s of
   Just v -> return v
   _      -> err "scientific number doesn't fit in the target representation"
 
-instance MonadThrow m => FromProp m CBool where
+instance Monad m => FromProp m CBool where
   fromProp = do
     b <- fromProp
     return $ if b then 1 else 0
 
-instance MonadThrow m => FromProp m CShort where
+instance Monad m => FromProp m CShort where
   fromProp = CShort <$> fromProp
 
-instance MonadThrow m => FromProp m CUShort where
+instance Monad m => FromProp m CUShort where
   fromProp = CUShort <$> fromProp
 
-instance MonadThrow m => FromProp m CInt where
+instance Monad m => FromProp m CInt where
   fromProp = CInt <$> fromProp
 
-instance MonadThrow m => FromProp m CUInt where
+instance Monad m => FromProp m CUInt where
   fromProp = CUInt <$> fromProp
 
-instance MonadThrow m => FromProp m CLong where
+instance Monad m => FromProp m CLong where
   fromProp = CLong <$> fromProp
 
-instance MonadThrow m => FromProp m CULong where
+instance Monad m => FromProp m CULong where
   fromProp = CULong <$> fromProp
 
-instance MonadThrow m => FromProp m CLLong where
+instance Monad m => FromProp m CLLong where
   fromProp = CLLong <$> fromProp
 
-instance MonadThrow m => FromProp m CULLong where
+instance Monad m => FromProp m CULLong where
   fromProp = CULLong <$> fromProp
 
-instance MonadThrow m => FromProp m CFloat where
+instance Monad m => FromProp m CFloat where
   fromProp = CFloat <$> fromProp
 
-instance MonadThrow m => FromProp m CDouble where
+instance Monad m => FromProp m CDouble where
   fromProp = CDouble <$> fromProp
 
diff --git a/src/Salak/Internal/Source.hs b/src/Salak/Internal/Source.hs
--- a/src/Salak/Internal/Source.hs
+++ b/src/Salak/Internal/Source.hs
@@ -30,16 +30,8 @@
   , reload :: IO ReloadResult
   }
 
--- | Monad has the ability to get a `SourcePack` instance.
-class Monad m => MonadSalak m where
-  askSalak :: m SourcePack
-
--- | Get reload action which used for reload profiles
-askReload :: MonadSalak m => m (IO ReloadResult)
-askReload = reload <$> askSalak
-
 diff :: Source -> Source -> T.Trie ModType
-diff = T.merge go
+diff = T.unionWith' go
   where
     go Nothing Nothing = Nothing
     go (Just (Vals a)) Nothing  = if H.null a then Nothing else Just Add
@@ -82,7 +74,7 @@
 search2 = foldl search1
 
 search1 :: Source -> Key -> Source
-search1 (T.Trie _ m) key = fromMaybe T.empty $ HM.lookup key m
+search1 m key = fromMaybe T.empty $ HM.lookup key $ T.getMap m
 
 fmt :: ModType -> Int -> String -> String -> String
 fmt m i s n = concat ['#' : show i, ' ' : show m, ' ' : s ,  ' ' : n]
@@ -99,7 +91,7 @@
     go (Just (e1,v1)) (Just (e2,v2)) = Just (e1++e2, modVals' v2 v1)
 
 setVal :: ToValue v => Int -> v -> TraceSource -> TraceSource
-setVal i v (T.Trie x m) = T.Trie (go x) m
+setVal i v = T.update go
   where
     go Nothing       = Just ([], modVals (Val i $ toVal v) emptyVals)
     go (Just (e,vs)) = Just (e,  modVals (Val i $ toVal v) vs)
diff --git a/src/Salak/Trie.hs b/src/Salak/Trie.hs
--- a/src/Salak/Trie.hs
+++ b/src/Salak/Trie.hs
@@ -1,7 +1,44 @@
 {-# LANGUAGE DeriveFunctor     #-}
 {-# LANGUAGE NoImplicitPrelude #-}
-module Salak.Trie where
+-- |
+-- Module:      Salak.Internal
+-- Copyright:   2019 Daniel YU
+-- License:     BSD3
+-- Maintainer:  leptonyu@gmail.com
+-- Stability:   experimental
+-- Portability: portable
+--
+-- A data structure for manipulating properties.
+--
+module Salak.Trie(
+    Trie
+  , getPrimitive
+  , getMap
+  -- * Construction
+  , empty
+  , singleton
+  -- * Basic interface
+  , Salak.Trie.null
+  , member
+  , lookup
+  , insert
+  , modify
+  , modifyF
+  , modify'
+  , update
+  , alter
+  , alterF
+  -- * Lists
+  , Salak.Trie.toList
+  , fromList
+  -- * Filter
+  , filter
+  -- * Combine
+  , unionWith
+  , unionWith'
+  ) where
 
+import           Control.Applicative (pure, (<*>))
 import           Control.Monad       (Monad (..))
 import           Data.Bool
 import           Data.Eq
@@ -12,30 +49,56 @@
 import qualified Data.HashMap.Strict as HM
 import           Data.List           (concat, intercalate, map, reverse, (++))
 import           Data.Maybe
+import           Data.Traversable
 import           Data.Tuple          (uncurry)
 import           Salak.Internal.Key
 import           Text.Show           (Show (..))
 
+-- | A Trie from keys `Key` to values @v@, which is a recursive map.
 data Trie v = Trie !(Maybe v) !(HashMap Key (Trie v)) deriving (Eq, Functor)
 
 instance Show v => Show (Trie v) where
   show t = intercalate "\n" $ map (\(k,v)-> show k ++ ":" ++ show v) $ Salak.Trie.toList t
 
-empty :: Trie v
-empty = Trie Nothing HM.empty
-
-null :: Eq v => Trie v -> Bool
-null = (== empty)
-
 instance Foldable Trie where
   foldr f b (Trie v m) = foldr (flip (foldr f)) (go v) m
     where
       go (Just x) = f x b
       go _        = b
 
+instance Traversable Trie where
+  traverse f (Trie v m) = Trie <$> go v <*> traverse (traverse f) m
+    where
+      go (Just x) = Just <$> f x
+      go _        = pure Nothing
+
+-- | /O(1)/. A trie with a single element.
+singleton :: v -> Trie v
+singleton v = Trie (Just v) HM.empty
+
+-- | /O(1)/. The empty trie.
+empty :: Trie v
+empty = Trie Nothing HM.empty
+
+-- | Get primitive value of a trie.
+getPrimitive :: Trie v -> Maybe v
+getPrimitive (Trie v _) = v
+
+-- | Get map value of a trie.
+getMap :: Trie v -> HashMap Key (Trie v)
+getMap (Trie _ m) = m
+
+-- | /O(1)/. Return True if this trie is empty, False otherwise.
+null :: Trie v -> Bool
+null (Trie Nothing e) = HM.null e
+null _                = False
+
+-- | /O(log (n+m))/. Return True if the specified key is present in the trie, False otherwise.
 member :: Eq v => Keys -> Trie v -> Bool
 member k t = isJust (lookup k t)
 
+-- | /O(log (n+m))/. Return the primitive value to which the specified key is mapped,
+-- or Nothing if this trie contains no mapping for the key.
 lookup :: Eq v => Keys -> Trie v -> Maybe v
 lookup (Keys keys) = go keys
   where
@@ -44,24 +107,33 @@
       Just t -> go ks t
       _      -> Nothing
 
+-- | /O(log n)/. Associate the specified value with the specified key in this trie.
+-- If this trie previously contained a mapping for the key, the old value is replaced.
 insert :: Eq v => Keys -> v -> Trie v -> Trie v
 insert ks v = alter (\_ -> Just v) ks
 
+-- | /O(log m)/. The expression (`modify` k f trie) modifies the sub trie at k.
 modify :: Eq v => Key -> (Trie v -> Trie v) -> Trie v -> Trie v
 modify k f (Trie v m) = Trie v $ HM.alter (go . f . fromMaybe empty) k m
   where
     go x = if x == empty then Nothing else Just x
 
-
+-- | /O(log (n+m))/. The expression (`modify'` ks f trie) modifies the sub trie at ks.
 modify' :: Eq v => Keys -> (Trie v -> Trie v) -> Trie v -> Trie v
 modify' (Keys ks) f = foldr modify f ks
 
+-- | /O(log m)/. The expression (`modifyF` k f trie) modifies the sub trie at k.
 modifyF :: (Monad m, Eq v) => Key -> (Trie v -> m (Trie v)) -> Trie v -> m (Trie v)
 modifyF k f (Trie v m) = Trie v <$> HM.alterF go k m
   where
     go (Just w) = (\x -> if x == empty then Nothing else Just x) <$> f w
     go _        = return Nothing
 
+-- | /O(1)/. The expression (update f trie) updates the primitive value in the trie.
+update :: Eq v => (Maybe v -> Maybe v) -> Trie v -> Trie v
+update f = alter f (Keys [])
+
+-- | /O(n)/. The expression (update f ks trie) updates the primitive value of sub trie at ks.
 alter :: Eq v => (Maybe v -> Maybe v) -> Keys -> Trie v -> Trie v
 alter f (Keys keys) = go keys
   where
@@ -69,6 +141,7 @@
     go (k:ks) (Trie v m) = Trie v $ HM.alter (g2 ks) k m
     g2 ks t = let t1 = go ks (fromMaybe empty t) in if t1 == empty then Nothing else Just t1
 
+-- | /O(n)/. The expression (update f ks trie) updates the primitive value of sub trie at ks.
 alterF :: (Functor f, Eq v) => (Maybe v -> f(Maybe v)) -> Keys -> Trie v -> f (Trie v)
 alterF f (Keys keys) = go keys
   where
@@ -77,6 +150,7 @@
     g2 ks t = g3 <$> go ks (fromMaybe empty t)
     g3 t = if t == empty then Nothing else Just t
 
+-- | /O(n*m)/. Return a list of this tries's elements. The list is produced lazily.
 toList :: Trie v -> [(Keys, v)]
 toList = go []
   where
@@ -85,9 +159,12 @@
     g2 p m = concat $ g3 p <$> HM.toList m
     g3 p (k,t) = go (k:p) t
 
+-- | /O(n*m*log n)/. Construct a trie with the supplied mappings.
+-- If the list contains duplicate mappings, the later mappings take precedence.
 fromList :: Eq v => [(Keys, v)] -> Trie v
 fromList = foldr (uncurry insert) empty
 
+-- | /O(n)/. Filter this trie by retaining only elements which values satisfy a predicate.
 filter :: Eq v => (v -> Bool) -> Trie v -> Trie v
 filter f (Trie v m) = if ok v then Trie v go else Trie Nothing go
   where
@@ -96,18 +173,18 @@
     go = HM.mapMaybe (g2 . filter f) m
     g2 x = if x == empty then Nothing else Just x
 
-partition :: Eq v => (v -> Bool) -> Trie v -> (Trie v, Trie v)
-partition f t = (filter f t, filter (not.f) t)
-
+-- | /O(n+m)/. The union of two tries.
+-- If a key occurs in both tries, the provided function (first argument) will be used to compute the result.
 unionWith :: Eq v => (Maybe v -> Maybe v -> Maybe v) -> Trie v -> Trie v -> Trie v
 unionWith f (Trie v1 m1) (Trie v2 m2) = Trie (f v1 v2) $ HM.unionWith (unionWith f) m1 m2
 
-
-merge :: (Maybe v -> Maybe v -> Maybe v3) -> Trie v -> Trie v -> Trie v3
-merge f (Trie v1 m1) (Trie v2 m2) = Trie (f v1 v2) $ foldr go HM.empty $ HM.keys $ HM.union m1 m2
+-- | /O(n+m)/. The union of two tries.
+-- All the keys will be calculated by the provided function.
+unionWith' :: (Maybe v -> Maybe v -> Maybe v3) -> Trie v -> Trie v -> Trie v3
+unionWith' f (Trie v1 m1) (Trie v2 m2) = Trie (f v1 v2) $ foldr go HM.empty $ HM.keys $ HM.union m1 m2
   where
     go k =
       let x1 = fromMaybe empty $ HM.lookup k m1
           x2 = fromMaybe empty $ HM.lookup k m2
-      in HM.insert k (merge f x1 x2)
+      in HM.insert k (unionWith' f x1 x2)
 
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -9,7 +9,6 @@
 
 module Main where
 
-import           Control.Monad.Catch
 import           Control.Monad.Writer
 import           Data.List             (intercalate)
 import           Data.Text             (Text, pack, unpack)
@@ -47,17 +46,17 @@
   { hello :: IO Int
   } deriving Generic
 
-instance (MonadThrow m, MonadIO m) => FromProp m Hello
+instance MonadIO m => FromProp m Hello
 
 data Config = Config
   { level :: IO Int
   , world :: Maybe Bool
   }
 
-instance (MonadIO m, MonadCatch m) => FromProp m Config where
+instance MonadIO m => FromProp m Config where
   fromProp = Config <$> "level" .?= (return 1) <*> "world"
 
-loadRandom :: MonadIO m => Text -> LoadSalakT m ()
+loadRandom :: (MonadThrow m, MonadIO m) => Text -> LoadSalakT m ()
 loadRandom key = loadList True (unpack key) go
   where
     go = do
