diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@
   , ext  :: Int
   } deriving (Eq, Show)
 
-instance Monad m => FromProp m Config where
+instance FromProp m Config where
   fromProp = Config
     <$> "user" ? pattern "[a-z]{5,16}"
     <*> "pwd"
@@ -90,7 +90,7 @@
 λ> 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
+λ> instance 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,6 +1,6 @@
 cabal-version: 1.12
 name: salak
-version: 0.3.3.1
+version: 0.3.3.2
 license: MIT
 license-file: LICENSE
 copyright: 2019 Daniel YU
@@ -26,7 +26,9 @@
         Salak.Internal.Prop
         Salak.Internal.Writable
     default-language: Haskell2010
-    default-extensions: RecordWildCards TupleSections
+    default-extensions: RecordWildCards TupleSections OverloadedStrings
+                        ScopedTypeVariables FlexibleInstances MultiParamTypeClasses
+                        DeriveGeneric
     ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures
     build-depends:
         attoparsec >=0.13.2.2 && <0.14,
@@ -35,6 +37,7 @@
         containers >=0.6.0.1 && <0.7,
         data-default >=0.7.1.1 && <0.8,
         directory >=1.3.3.0 && <1.4,
+        dlist >=0.8.0.7 && <0.9,
         exceptions >=0.10.2 && <0.11,
         filepath >=1.4.2.1 && <1.5,
         hashable >=1.2.7.0 && <1.3,
@@ -50,8 +53,12 @@
 test-suite spec
     type: exitcode-stdio-1.0
     main-is: Spec.hs
+    build-tool-depends: hspec-discover:hspec-discover -any
     hs-source-dirs: test src
     other-modules:
+        Salak.Internal.KeySpec
+        Salak.Internal.PropSpec
+        Salak.Internal.SourceSpec
         Salak
         Salak.Internal
         Salak.Internal.Key
@@ -62,7 +69,9 @@
         Salak.Trie
         Paths_salak
     default-language: Haskell2010
-    default-extensions: RecordWildCards TupleSections
+    default-extensions: RecordWildCards TupleSections OverloadedStrings
+                        ScopedTypeVariables FlexibleInstances MultiParamTypeClasses
+                        DeriveGeneric
     ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures
     build-depends:
         QuickCheck >=2.13.2 && <2.14,
@@ -72,6 +81,7 @@
         containers >=0.6.0.1 && <0.7,
         data-default >=0.7.1.1 && <0.8,
         directory >=1.3.3.0 && <1.4,
+        dlist >=0.8.0.7 && <0.9,
         exceptions >=0.10.2 && <0.11,
         filepath >=1.4.2.1 && <1.5,
         hashable >=1.2.7.0 && <1.3,
diff --git a/src/Salak.hs b/src/Salak.hs
--- a/src/Salak.hs
+++ b/src/Salak.hs
@@ -108,7 +108,7 @@
   , configDir :: Maybe FilePath
   }
 
-instance Monad m => FromProp m FileConfig where
+instance FromProp m FileConfig where
   fromProp = FileConfig
     <$> "name" .?= Nothing
     <*> "dir"  .?= Nothing
@@ -210,7 +210,7 @@
 -- >>> 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
+-- >>> instance 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
@@ -42,6 +42,7 @@
   , Keys(..)
   , Key(..)
   , simpleKeys
+  , fromKeys
   , ToKeys(..)
   , setVal
   , Val(..)
@@ -100,7 +101,7 @@
 liftNT a = MS.get >>= liftIO . runLoad a
 
 instance MonadIO m => MonadSalak (LoadSalakT m) where
-  askSalak = MS.get >>= toSourcePack
+  askSourcePack = MS.get >>= toSourcePack
   setLogF f = do
     UpdateSource{..} <- MS.get
     liftIO $ void $ swapMVar lfunc f
@@ -125,9 +126,10 @@
 runRun :: Monad m => RunSalakT m a -> SourcePack -> m a
 runRun (RunSalakT ma) = runReaderT ma
 
-instance Monad m => MonadSalak (RunSalakT m) where
-  askSalak = RunSalakT ask
 
+instance MonadIO m => MonadSalak (RunSalakT m) where
+  askSourcePack = ask
+
 instance (MonadThrow m, IU.MonadUnliftIO m) => IU.MonadUnliftIO (RunSalakT m) where
   askUnliftIO = do
     ut <- ask
@@ -172,7 +174,7 @@
   runLoad (lm >> MS.get) (UpdateSource r 0 HM.empty l q u) >>= toSourcePack
 
 toSourcePack :: MonadIO m => UpdateSource -> m SourcePack
-toSourcePack UpdateSource{..} = liftIO (readMVar ref) >>= \s -> return $ SourcePack s [] qfunc lfunc go
+toSourcePack UpdateSource{..} = liftIO (readMVar ref) >>= \s -> return $ SourcePack s mempty qfunc lfunc go
   where
     go = do
       t        <- readMVar ref
diff --git a/src/Salak/Internal/Key.hs b/src/Salak/Internal/Key.hs
--- a/src/Salak/Internal/Key.hs
+++ b/src/Salak/Internal/Key.hs
@@ -1,9 +1,14 @@
+{-# LANGUAGE CPP               #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Salak.Internal.Key(
     Key(..)
   , Keys(..)
+  , mempty
   , simpleKeys
+  , singletonKey
+  , fromKeys
+  , toKeyList
   , ToKeys(..)
   , isNum
   , isStr
@@ -11,11 +16,14 @@
 
 import           Control.Applicative  ((<|>))
 import           Data.Attoparsec.Text
-import           Data.Coerce          (coerce)
+import qualified Data.DList           as D
 import           Data.Hashable
 import           Data.List            (intercalate)
 import           Data.Text            (Text)
 import qualified Data.Text            as T
+#if __GLASGOW_HASKELL__ < 804
+import           Data.Semigroup
+#endif
 
 data Key
   = KT !Text
@@ -28,10 +36,29 @@
   compare (KI _) _      = LT
   compare _      _      = GT
 
-newtype Keys = Keys { unKeys :: [Key] } deriving Eq
+newtype Keys = Keys { unKeys :: D.DList Key } deriving Eq
 
+emptyKey :: Keys
+emptyKey = Keys D.empty
+
+singletonKey :: Key -> Keys
+singletonKey k = fromKeys [k]
+
+fromKeys :: [Key] -> Keys
+fromKeys = Keys . D.fromList
+
+toKeyList :: Keys -> [Key]
+toKeyList = D.toList . unKeys
+
+instance Semigroup Keys where
+  (Keys a) <> (Keys b) = Keys $ a <> b
+
+instance Monoid Keys where
+  mempty = emptyKey
+  mappend = (<>)
+
 instance Show Keys where
-  show ks = toKey (coerce ks)
+  show = toKey . D.toList . unKeys
     where
       toKey = intercalate "." . go
       go (a@(KT _):cs) = let (b,c) = break isStr cs in (show a ++ concat (show <$> b)) : go c
@@ -56,8 +83,8 @@
   show (KT x) = T.unpack x
   show (KI i) = "[" ++ show i ++ "]"
 
-simpleKeys :: Text -> [Key]
-simpleKeys as = fmap KT $ filter (not.T.null) $ T.splitOn "." as
+simpleKeys :: Text -> Keys
+simpleKeys = fromKeys . fmap KT . filter (not.T.null) . T.splitOn "."
 
 exprs :: Parser [Key]
 exprs = concat <$> ( (expr <|> return []) `sepBy` char '.')
@@ -91,7 +118,7 @@
   toKeys = Right
 
 instance ToKeys Text where
-  toKeys = fmap Keys . selectors
+  toKeys = fmap fromKeys . selectors
     where
       selectors = go . parse exprs . flip T.snoc '\n'
       go (Done i r) = if i /= "\n" then Left $ "uncomplete parse" ++ T.unpack i else Right r
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
@@ -17,6 +17,7 @@
 import           Control.Monad
 import           Control.Monad.Catch
 import           Control.Monad.Except
+import           Control.Monad.Fail
 import           Control.Monad.Identity  (Identity (..))
 import           Control.Monad.Reader
 import qualified Data.ByteString         as B
@@ -26,7 +27,7 @@
 import           Data.Hashable           (Hashable)
 import qualified Data.HashMap.Strict     as HM
 import           Data.Int
-import           Data.List               (sortBy)
+import           Data.List               (sort)
 import qualified Data.Map.Strict         as M
 import           Data.Maybe
 import           Data.Menshen
@@ -47,44 +48,26 @@
 import           Salak.Internal.Val
 import qualified Salak.Trie              as TR
 import           Text.Read               (readMaybe)
-
-class Monad m => FromProp m a where
-  fromProp :: Prop m a
-  default fromProp :: (Generic a, GFromProp m (Rep a)) => Prop m a
-  fromProp = fmap to gFromProp
-
-newtype Prop m a
-  = Prop { unProp :: ReaderT SourcePack (ExceptT SomeException m) a }
-  deriving (Functor, Applicative, Monad, MonadReader SourcePack, MonadIO)
-
-instance MonadTrans Prop where
-  lift = Prop . lift . lift
-
-instance Monad m => A.Alternative (Prop m) where
-  empty = notFound
-  a <|> b = do
-    v <- try a
-    case v of
-      Right x                   -> return x
-      Left (_ :: SomeException) -> b
+import           Unsafe.Coerce           (unsafeCoerce)
 
 -- | Core type class of salak, which provide function to parse properties.
 class Monad m => MonadSalak m where
-  -- | Monad has the ability to get a `SourcePack` instance.
-  askSalak :: m SourcePack
 
+  -- | Monad has the ability to get a SourcePack instance.
+  askSourcePack :: m SourcePack
+
   -- | Get reload action which used for reload profiles
   askReload :: m (IO ReloadResult)
-  askReload = reload <$> askSalak
+  askReload = reload <$> askSourcePack
 
   setLogF :: MonadIO m => (String -> IO ()) -> m ()
   setLogF f = do
-    SourcePack{..} <- askSalak
+    SourcePack{..} <- askSourcePack
     liftIO $ void $ swapMVar lref f
 
   logSalak :: MonadIO m => String -> m ()
   logSalak msg = do
-    SourcePack{..} <- askSalak
+    SourcePack{..} <- askSourcePack
     liftIO $ do
       f <- readMVar lref
       f msg
@@ -99,55 +82,98 @@
   -- `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 $ SalakException (unpack ks) (toException $ PropException e)
-      Right (k,t) -> do
-        v <- runProp2 sp { source = t, pref = pref ++ unKeys k} fromProp
-        case v of
-          Left  e -> case fromException e of
-            Just (SalakException a b) -> throwM $ SalakException a  b
-            Just pe                   -> throwM $ SalakException (unpack ks) (toException pe)
-            _                         -> throwM $ SalakException (unpack ks) e
-          Right x -> return x
+  require ks = askSourcePack >>= \s -> runProp s $ do
+    case toKeys ks of
+      Left  e -> failKey (unpack ks) (PropException e)
+      Right k -> withKeys k fromProp
 
-instance {-# OVERLAPPABLE #-} (m ~ t m', Monad m', Monad m, MonadTrans t, MonadSalak m') => MonadSalak m where
-  askSalak = lift askSalak
+-- | Property parser, used to parse property from `Value`
+newtype Prop m a
+  = Prop { unProp :: ReaderT SourcePack (ExceptT SomeException m) a }
+  deriving (Functor, Applicative, Monad, MonadReader SourcePack, MonadIO)
 
-instance Monad m => MonadSalak (Prop m) where
-  askSalak = Prop ask
+runProp :: MonadThrow m => SourcePack -> Prop m a -> m a
+runProp sp (Prop p) = do
+  v <- runExceptT (runReaderT p sp)
+  case v of
+    Left  e -> throwM e
+    Right x -> return x
 
+withProp :: (SourcePack -> SourcePack) -> Prop m a -> Prop m a
+withProp = unsafeCoerce withReaderT
+
+withKey :: Key -> Prop m a -> Prop m a
+withKey = withKeys . singletonKey
+
+withKeys :: Keys -> Prop m a -> Prop m a
+withKeys key = withProp
+  $ \SourcePack{..} ->
+     SourcePack{pref = pref <> key, source = TR.subTries key source, ..}
+
+data SalakException
+  = PropException String -- ^ Parse failed
+  | NullException        -- ^ Not found
+  | SalakException String SomeException
+  deriving Show
+
+instance Exception SalakException
+
+
+failKey :: Monad m => String -> SalakException -> Prop m a
+failKey ks e = do
+  SourcePack{..} <- ask
+  throwM
+    $ SalakException (go (show pref) ks)
+    $ toException e
+  where
+    go "" a = a
+    go a "" = a
+    go a  b = a <> "." <> b
+
+-- | Automatic convert literal string into an instance of `Prop` @m@ @a@.
+instance (Monad m, FromProp m a) => IsString (Prop m a) where
+  fromString ks = do
+    case toKeys ks of
+      Left  e -> failKey ks (PropException e)
+      Right k -> withKeys k fromProp
+
+
+instance MonadTrans Prop where
+  lift = Prop . lift . lift
+
+instance Monad m => A.Alternative (Prop m) where
+  empty = failKey "" NullException
+
+  a <|> b = do
+    v <- try a
+    case v of
+      Right x                   -> return x
+      Left (_ :: SomeException) -> b
+
+instance Monad m => MonadError SomeException (Prop m) where
+  throwError = Prop . lift . throwError . toException
+  catchError (Prop ma) me = Prop $ do
+    c <- ask
+    lift $ catchError (runReaderT ma c) (\e -> runReaderT (unProp $ me e) c)
+
 instance Monad m => MonadThrow (Prop m) where
-  throwM = Prop . lift . throwError . toException
+  throwM = throwError . toException
 
 instance Monad m => MonadCatch (Prop m) where
-  catch (Prop a) f = do
-    sp <- ask
-    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
+  catch ma me = catchError ma (\e -> maybe (throwM e) me $ fromException e)
 
-runProp2 :: Monad m => SourcePack -> Prop m a -> m (Either SomeException a)
-runProp2 sp (Prop p) = runExceptT (runReaderT p sp)
+instance Monad m => MonadFail (Prop m) where
+  fail = failKey "" . PropException
 
-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
+-- | Type class used to parse properties.
+class FromProp m a where
 
+  -- | Parse properties from `Value`.
+  fromProp :: Monad m => Prop m a
+  default fromProp :: (Generic a, GFromProp m (Rep a), Monad m) => Prop m a
+  fromProp = fmap to gFromProp
+
 instance FromProp m a => FromProp m (Maybe a) where
   fromProp = do
     v <- try fromProp
@@ -162,7 +188,6 @@
 
 instance FromProp m a => FromProp m (Either String a) where
   fromProp = do
-    SourcePack{..} <- ask
     v <- try fromProp
     return $ case v of
       Left  e -> Left $ show (e :: SomeException)
@@ -170,19 +195,15 @@
 
 instance {-# OVERLAPPABLE #-} FromProp m a => FromProp m [a] where
   fromProp = do
-    sp@SourcePack{..} <- askSalak
-    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
+    SourcePack{..} <- ask
+    sequence $ (`withKey` fromProp) <$> sort (filter isNum $ HM.keys $ TR.getMap source)
 
 instance {-# OVERLAPPABLE #-} (IsString s, FromProp m a) => FromProp m [(s, a)] where
   fromProp = do
-    sp@SourcePack{..} <- askSalak
-    foldM (go sp) [] $ sortBy g2 $ filter (isStr.fst) $ HM.toList $ TR.getMap source
+    SourcePack{..} <- ask
+    sequence $ go <$> sort (filter isStr $ HM.keys $ TR.getMap source)
     where
-      go s vs (k,t) = (:vs) . (fromString $ show $ Keys [k],) <$> runProp s { pref = pref s ++ [k], source = t} fromProp
-      g2 (a,_) (b,_) = compare b a
+      go k = (fromString $ show $ singletonKey k,) <$> withKey k fromProp
 
 instance (Eq s, Hashable s, IsString s, FromProp m a) => FromProp m (HM.HashMap s a) where
   fromProp = HM.fromList <$> fromProp
@@ -201,8 +222,7 @@
 buildIO sp a = liftIO $ do
   aref <- newMVar a
   modifyMVar_ (qref sp) $ \f -> return $ \s ->
-    let b = runProp1 sp {source = search2 s (pref sp), pref = pref sp} fromProp
-    in case b of
+    case runProp sp {source = s} $ withKeys (pref sp) fromProp of
       Left  e -> Left $ show e
       Right v -> do
         vb <- v
@@ -210,34 +230,7 @@
         return (swapMVar aref (fromMaybe a vb) >> io)
   return (readMVar aref)
 
-data SalakException
-  = PropException String -- ^ Parse failed
-  | NullException        -- ^ Not found
-  | SalakException String SomeException
-  deriving Show
 
-instance Exception SalakException
-
--- | 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
-    case search ks source of
-      Left  e     -> throwM $ SalakException
-        (if null pref then ks else show (Keys pref) ++ "." ++ ks)
-        (toException $ PropException e)
-      Right (k,t) -> runProp sp { source = t, pref = pref ++ unKeys k} fromProp
-
-notFound :: Monad m => Prop m a
-notFound = do
-  SourcePack{..} <- askSalak
-  throwM $ SalakException (show (Keys pref)) $ toException NullException
-
-err :: Monad m => String -> Prop m a
-err e = do
-  SourcePack{..} <- askSalak
-  throwM $ PropException $ show (Keys pref) ++ ":" ++ e
-
 -- | Prop operators.
 --
 -- Suppose we have the following definition:
@@ -276,24 +269,24 @@
 -- | Support for setting default `IO` value.
 instance (MonadIO m, FromProp (Either SomeException) a) => PropOp (Prop m) (IO a) where
   (.?=) ma a = do
-    sp <- askSalak
+    sp <- ask
     v  <- try ma
     case v of
       Left  (_ :: SomeException) -> liftIO a >>= buildIO sp
       Right o                    -> return o
 
 instance Monad m => HasValid (Prop m) where
-  invalid = err . toI18n
+  invalid = Control.Monad.Fail.fail . toI18n
 
 -- | Parse primitive value from `Value`
 readPrimitive :: Monad m => (Value -> Either String a) -> Prop m a
 readPrimitive f = do
-  SourcePack{..} <- askSalak
+  SourcePack{..} <- ask
   vx <- g $ TR.getPrimitive source >>= getVal
   case f <$> vx of
-    Just (Left e)  -> err e
+    Just (Left e)  -> Control.Monad.Fail.fail e
     Just (Right a) -> return a
-    _              -> notFound
+    _              -> A.empty
   where
     g = return
 
@@ -305,29 +298,27 @@
     go _ x      = Left $ fst (typeOfV x) ++ " cannot convert to enum"
 
 
-class Monad m => GFromProp m f where
-  gFromProp :: Prop m (f a)
+class GFromProp m f where
+  gFromProp :: Monad m => Prop m (f a)
 
-instance {-# OVERLAPPABLE #-} (Monad m, Constructor c, GFromProp m a) => GFromProp m (M1 C c a) where
+instance {-# OVERLAPPABLE #-} (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 :: (Monad m, GFromProp m f) => Text -> Prop m (f a)
+gEnum :: (GFromProp m f, Monad m) => Text -> Prop m (f a)
 gEnum va = do
   o <- gFromProp
   readEnum $ \x -> if x==va then Right o else Left "enum invalid"
 
 instance {-# OVERLAPPABLE #-} (Selector s, GFromProp m a) => GFromProp m(M1 S s a) where
-  gFromProp = Prop $ do
-    let k = KT $ T.pack $ selName (undefined :: t s a p)
-    withReaderT (\s -> s { pref = pref s ++ [k], source = search1 (source s) k }) $ unProp $ M1 <$> gFromProp
+  gFromProp = withKey (KT $ T.pack $ selName (undefined :: t s a p)) $ M1 <$> gFromProp
 
 instance {-# OVERLAPPABLE #-} GFromProp m a => GFromProp m (M1 D i a) where
   gFromProp = M1 <$> gFromProp
 
-instance {-# OVERLAPPABLE #-} (FromProp m a) => GFromProp m (K1 i a) where
+instance {-# OVERLAPPABLE #-} FromProp m a => GFromProp m (K1 i a) where
     gFromProp = fmap K1 fromProp
 
 instance Monad m => GFromProp m U1 where
@@ -336,62 +327,62 @@
 instance {-# OVERLAPPABLE #-} (GFromProp m a, GFromProp m b) => GFromProp m (a:*:b) where
   gFromProp = (:*:) <$> gFromProp <*> gFromProp
 
-instance {-# OVERLAPPABLE #-} (Monad m, GFromProp m a, GFromProp m b) => GFromProp m (a:+:b) where
+instance {-# OVERLAPPABLE #-} (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
+instance FromProp m a => FromProp m (Identity a) where
   fromProp = Identity <$> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b) => FromProp m (a,b) where
+instance (FromProp m a, FromProp m b) => FromProp m (a,b) where
   fromProp = (,) <$> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c) => FromProp m(a,b,c) where
+instance (FromProp m a, FromProp m b, FromProp m c) => FromProp m(a,b,c) where
   fromProp = (,,) <$> fromProp <*> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d) => FromProp m(a,b,c,d) where
+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d) => FromProp m(a,b,c,d) where
   fromProp = (,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e) => FromProp m(a,b,c,d,e) where
+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e) => FromProp m(a,b,c,d,e) where
   fromProp = (,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f) => FromProp m(a,b,c,d,e,f) where
+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f) => FromProp m(a,b,c,d,e,f) where
   fromProp = (,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g) => FromProp m(a,b,c,d,e,f,g) where
+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g) => FromProp m(a,b,c,d,e,f,g) where
   fromProp = (,,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h) => FromProp m(a,b,c,d,e,f,g,h) where
+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h) => FromProp m(a,b,c,d,e,f,g,h) where
   fromProp = (,,,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp
 
-instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h, FromProp m i) => FromProp m(a,b,c,d,e,f,g,h,i) where
+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h, FromProp m i) => FromProp m(a,b,c,d,e,f,g,h,i) where
   fromProp = (,,,,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp
 
 
-instance (Monad m, FromProp m a) => FromProp m (Min a) where
+instance FromProp m a => FromProp m (Min a) where
   fromProp = Min <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (Max a) where
+instance FromProp m a => FromProp m (Max a) where
   fromProp = Max <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (First a) where
+instance FromProp m a => FromProp m (First a) where
   fromProp = First <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (Last a) where
+instance FromProp m a => FromProp m (Last a) where
   fromProp = Last <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (Dual a) where
+instance FromProp m a => FromProp m (Dual a) where
   fromProp = Dual <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (Sum a) where
+instance FromProp m a => FromProp m (Sum a) where
   fromProp = Sum <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (Product a) where
+instance FromProp m a => FromProp m (Product a) where
   fromProp = Product <$> fromProp
 
-instance (Monad m, FromProp m a) => FromProp m (Option a) where
+instance FromProp m a => FromProp m (Option a) where
   fromProp = Option <$> fromProp
 
-instance Monad m => FromProp m Bool where
+instance FromProp m Bool where
   fromProp = readPrimitive go
     where
       go (VB x) = Right x
@@ -403,25 +394,25 @@
         _       -> Left "string convert bool failed"
       go x      = Left $ getType x ++ " cannot be bool"
 
-instance Monad m => FromProp m Text where
+instance FromProp m Text where
   fromProp = readPrimitive go
     where
       go (VT x) = Right x
       go x      = Right $ T.pack $ snd $ typeOfV x
 
-instance Monad m => FromProp m TL.Text where
+instance FromProp m TL.Text where
   fromProp = TL.fromStrict <$> fromProp
 
-instance Monad m => FromProp m B.ByteString where
+instance FromProp m B.ByteString where
   fromProp = TB.encodeUtf8 <$> fromProp
 
-instance Monad m => FromProp m BL.ByteString where
+instance FromProp m BL.ByteString where
   fromProp = TBL.encodeUtf8 <$> fromProp
 
-instance Monad m => FromProp m String where
+instance FromProp m String where
   fromProp = T.unpack <$> fromProp
 
-instance Monad m => FromProp m Scientific where
+instance FromProp m Scientific where
   fromProp = readPrimitive go
     where
       go (VT x) = case readMaybe $ T.unpack x of
@@ -430,49 +421,49 @@
       go (VI x) = Right x
       go x      = Left $ getType x ++ " cannot be number"
 
-instance Monad m => FromProp m Float where
+instance FromProp m Float where
   fromProp = toRealFloat <$> fromProp
 
-instance Monad m => FromProp m Double where
+instance FromProp m Double where
   fromProp = toRealFloat <$> fromProp
 
-instance Monad m => FromProp m Integer where
+instance FromProp m Integer where
   fromProp = toInteger <$> (fromProp :: Prop m Int)
 
-instance Monad m => FromProp m Int where
+instance FromProp m Int where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Int8 where
+instance FromProp m Int8 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Int16 where
+instance FromProp m Int16 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Int32 where
+instance FromProp m Int32 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Int64 where
+instance FromProp m Int64 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Word where
+instance FromProp m Word where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Word8 where
+instance FromProp m Word8 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Word16 where
+instance FromProp m Word16 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Word32 where
+instance FromProp m Word32 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m Word64 where
+instance FromProp m Word64 where
   fromProp = fromProp >>= toNum
 
-instance Monad m => FromProp m NominalDiffTime where
+instance FromProp m NominalDiffTime where
   fromProp = fromInteger <$> fromProp
 
-instance Monad m => FromProp m DiffTime where
+instance FromProp m DiffTime where
   fromProp = fromInteger <$> fromProp
 
 instance (HasResolution a, Monad m) => FromProp m (Fixed a) where
@@ -481,40 +472,40 @@
 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"
+  _      -> Control.Monad.Fail.fail "scientific number doesn't fit in the target representation"
 
-instance Monad m => FromProp m CBool where
+instance FromProp m CBool where
   fromProp = do
     b <- fromProp
     return $ if b then 1 else 0
 
-instance Monad m => FromProp m CShort where
+instance FromProp m CShort where
   fromProp = CShort <$> fromProp
 
-instance Monad m => FromProp m CUShort where
+instance FromProp m CUShort where
   fromProp = CUShort <$> fromProp
 
-instance Monad m => FromProp m CInt where
+instance FromProp m CInt where
   fromProp = CInt <$> fromProp
 
-instance Monad m => FromProp m CUInt where
+instance FromProp m CUInt where
   fromProp = CUInt <$> fromProp
 
-instance Monad m => FromProp m CLong where
+instance FromProp m CLong where
   fromProp = CLong <$> fromProp
 
-instance Monad m => FromProp m CULong where
+instance FromProp m CULong where
   fromProp = CULong <$> fromProp
 
-instance Monad m => FromProp m CLLong where
+instance FromProp m CLLong where
   fromProp = CLLong <$> fromProp
 
-instance Monad m => FromProp m CULLong where
+instance FromProp m CULLong where
   fromProp = CULLong <$> fromProp
 
-instance Monad m => FromProp m CFloat where
+instance FromProp m CFloat where
   fromProp = CFloat <$> fromProp
 
-instance Monad m => FromProp m CDouble where
+instance 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
@@ -7,7 +7,6 @@
 import           Data.HashMap.Strict     (HashMap)
 import qualified Data.HashMap.Strict     as HM
 import qualified Data.Heap               as H
-import           Data.Maybe
 import           Salak.Internal.Key
 import           Salak.Internal.Val
 import qualified Salak.Trie              as T
@@ -27,7 +26,7 @@
 
 data SourcePack = SourcePack
   { source :: !Source
-  , pref   :: ![Key]
+  , pref   :: !Keys
   , qref   :: !(MVar QFunc)
   , lref   :: !(MVar LFunc)
   , reload :: !(IO ReloadResult)
@@ -61,23 +60,12 @@
 gen i = foldr go T.empty
   where
     go (k,v) x = case toKeys k of
-      Left  e  -> T.alter (g3 e) (Keys []) x
+      Left  e  -> T.alter (g3 e) mempty x
       Right k' -> T.alter (g2 $ Val i $ toVal v) k' x
     g2 v (Just (a,Vals c)) = Just (a, Vals $ H.insert v c)
     g2 v _                 = Just ([], Vals $ H.singleton v)
     g3 e (Just (a,c)) = Just (e:a,c)
     g3 e _            = Just ([e], Vals H.empty)
-
-search :: (ToKeys k) => k -> Source -> Either String (Keys, Source)
-search k t = fmap (go . unKeys) (toKeys k)
-  where
-    go ks = (Keys ks, foldl search1 t ks)
-
-search2 :: Source -> [Key] -> Source
-search2 = foldl search1
-
-search1 :: Source -> Key -> Source
-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]
diff --git a/src/Salak/Trie.hs b/src/Salak/Trie.hs
--- a/src/Salak/Trie.hs
+++ b/src/Salak/Trie.hs
@@ -21,13 +21,15 @@
   , Salak.Trie.null
   , member
   , lookup
+  , subTrie
+  , subTries
   , insert
   , modify
   , modifyF
   , modify'
   , update
   , alter
-  , alterF
+  -- , alterF
   -- * Lists
   , Salak.Trie.toList
   , fromList
@@ -41,13 +43,14 @@
 import           Control.Applicative (pure, (<*>))
 import           Control.Monad       (Monad (..))
 import           Data.Bool
+import qualified Data.DList          as D
 import           Data.Eq
 import           Data.Foldable       (Foldable (..))
 import           Data.Function
 import           Data.Functor
 import           Data.HashMap.Strict (HashMap)
 import qualified Data.HashMap.Strict as HM
-import           Data.List           (concat, intercalate, map, reverse, (++))
+import           Data.List           (concat, intercalate, map, (++))
 import           Data.Maybe
 import           Data.Traversable
 import           Data.Tuple          (uncurry)
@@ -97,15 +100,16 @@
 member :: Eq v => Keys -> Trie v -> Bool
 member k t = isJust (lookup k t)
 
+subTrie :: Key -> Trie v -> Trie v
+subTrie key = fromMaybe empty . HM.lookup key . getMap
+
+subTries :: Keys -> Trie v -> Trie v
+subTries ks v = foldl (flip subTrie) v (toKeyList ks)
+
 -- | /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
-    go []     (Trie v _) = v
-    go (k:ks) (Trie _ m) = case HM.lookup k m of
-      Just t -> go ks t
-      _      -> Nothing
+lookup keys = getPrimitive . subTries keys
 
 -- | /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.
@@ -120,7 +124,7 @@
 
 -- | /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
+modify' ks f = foldr modify f (toKeyList 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)
@@ -131,33 +135,29 @@
 
 -- | /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 [])
+update f = alter f mempty
 
 -- | /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
-    go []     (Trie v m) = Trie (f v) m
-    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
+alter f keys = modify' keys (\(Trie a b) -> Trie (f a) b)
 
 -- | /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
-    go []     (Trie v m) = (`Trie` m) <$> f v
-    go (k:ks) (Trie v m) = Trie v <$> HM.alterF (g2 ks) k m
-    g2 ks t = g3 <$> go ks (fromMaybe empty t)
-    g3 t = if t == empty then Nothing else Just t
+-- alterF :: (Functor f, Eq v) => (Maybe v -> f(Maybe v)) -> Keys -> Trie v -> f (Trie v)
+-- alterF f keys = modifyF
+  -- where
+  --   go D.Nil         (Trie v m) = (`Trie` m) <$> f v
+  --   go (D.Cons k ks) (Trie v m) = Trie v <$> HM.alterF (g2 ks) k m
+  --   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 []
+toList = go D.empty
   where
-    go p (Trie (Just v) m) = (Keys $ reverse p, v) : g2 p m
+    go p (Trie (Just v) m) = (Keys p, v) : g2 p m
     go p (Trie _        m) = g2 p m
     g2 p m = concat $ g3 p <$> HM.toList m
-    g3 p (k,t) = go (k:p) t
+    g3 p (k,t) = go (D.cons 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.
diff --git a/test/Salak/Internal/KeySpec.hs b/test/Salak/Internal/KeySpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Salak/Internal/KeySpec.hs
@@ -0,0 +1,37 @@
+module Salak.Internal.KeySpec where
+
+import           Data.List          (intercalate)
+import           Data.Text          (Text, pack, unpack)
+import           Salak.Internal.Key
+import           Test.Hspec
+import           Test.QuickCheck
+
+newtype SKey = SKey { unKey :: Text } deriving Show
+
+instance Arbitrary SKey where
+  arbitrary = do
+    key <- choose (1,20)
+    vs  <- vectorOf key $ do
+      k <- choose (1,20)
+      v <- vectorOf k $ choose ('a','z')
+      b <- choose (0,10) :: Gen Int
+      if b > 0 then return v else do
+        x <- choose (0,10) :: Gen Int
+        return (v ++ "[" ++ show x ++ "]")
+    return (SKey $ pack $ intercalate "." vs)
+
+
+spec :: SpecWith ()
+spec = do
+  context "selectors" $ do
+    it "normal" $ do
+      toKeys (""         :: Text) `shouldBe` Right mempty
+      toKeys ("."        :: Text) `shouldBe` Right mempty
+      toKeys (".."       :: Text) `shouldBe` Right mempty
+      toKeys ("xx"       :: Text) `shouldBe` Right (fromKeys $ [KT "xx"])
+      toKeys ("xx[0]"    :: Text) `shouldBe` Right (fromKeys $ [KT "xx", KI 0])
+      toKeys ("xx.yy"    :: Text) `shouldBe` Right (fromKeys $ [KT "xx", KT "yy"])
+      toKeys ("xx[0][1]" :: Text) `shouldBe` Right (fromKeys $ [KT "xx", KI 0, KI 1])
+      show (fromKeys $ KT "x" : (KI <$> [0..9])) `shouldBe` "x[0][1][2][3][4][5][6][7][8][9]"
+    it "QuickCheck" $ do
+      quickCheck $ \s -> let s' = unKey s in (show <$> toKeys s') `shouldBe` Right (unpack s')
diff --git a/test/Salak/Internal/PropSpec.hs b/test/Salak/Internal/PropSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Salak/Internal/PropSpec.hs
@@ -0,0 +1,37 @@
+module Salak.Internal.PropSpec where
+
+import           Control.Concurrent.MVar
+import           Data.Int
+import           Salak.Internal
+import           Salak.Internal.Source
+import           Salak.Internal.Val
+import qualified Salak.Trie              as T
+import           Test.Hspec
+-- import           Test.QuickCheck
+
+newSource :: Value -> Source
+newSource v = T.singleton $ modVals (Val 0 v) emptyVals
+
+newSourcePack :: Value -> IO SourcePack
+newSourcePack v = do
+  let source = newSource v
+      pref   = mempty
+      reload = return $ ReloadResult False []
+  qref <- newMVar $ \_ -> Right (return ())
+  lref <- newMVar $ \_ -> return ()
+  return SourcePack{..}
+
+spec :: SpecWith ()
+spec = do
+  context "VT" $ do
+    it "text" $ do
+      sp <- newSourcePack (VT "128")
+      let run :: forall m a. Monad m => RunSalakT m a -> m a
+          run = (`runRun` sp)
+      vInt   :: Int   <- run $ require ""
+      vInt32 :: Int32 <- run $ require ""
+      -- vInt8  :: Int8  <- run $ require ""
+      128 `shouldBe` vInt
+      128 `shouldBe` vInt32
+      -- print vInt8
+
diff --git a/test/Salak/Internal/SourceSpec.hs b/test/Salak/Internal/SourceSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Salak/Internal/SourceSpec.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE NoOverloadedLists #-}
+module Salak.Internal.SourceSpec where
+
+import           Control.Monad.Writer
+import           Data.Text             (Text, unpack)
+import           GHC.Generics
+import           Salak
+import           Salak.Internal
+import           Salak.Internal.Source
+import qualified Salak.Trie            as T
+import           System.Random         (randomIO)
+import           Test.Hspec
+import           Test.QuickCheck
+
+
+data Config = Config
+  { level :: IO Int
+  , world :: Maybe Bool
+  }
+
+instance MonadIO m => FromProp m Config where
+  fromProp = Config <$> "level" .?= (return 1) <*> "world"
+
+data Hello = Hello
+  { hello :: IO Int
+  } deriving Generic
+
+instance MonadIO m => FromProp m Hello
+
+loadRandom :: (MonadThrow m, MonadIO m) => Text -> LoadSalakT m ()
+loadRandom key = loadList True (unpack key) go
+  where
+    go = do
+      a :: Int <- randomIO
+      return [(key, a)]
+
+spec :: SpecWith ()
+spec = do
+  context "source" $ do
+    it "normal - 2" $ do
+      let (_,b,c) = extract T.empty $ gen 0 ([("hello", "world")] :: [(Text, Text)])
+      length c `shouldBe` 0
+      length (T.toList b) `shouldBe` 1
+    it "normal - 2" $ do
+      let (_,b,c) = extract T.empty $ gen 0 ([("hello.value", "world")] :: [(Text, Text)])
+      length c `shouldBe` 0
+      length (T.toList b) `shouldBe` 1
+  context "Reload test" $ do
+    it "reload" $ do
+      loadAndRunSalak (loadRandom "hello") $ do
+        Hello{..}  <- require ""
+        Config{..} <- require ""
+        x  <- liftIO hello
+        liftIO $ print x
+        liftIO $ print world
+        q1 <- liftIO level
+        r  <- askReload
+        lift $ quickCheck $ \(_ :: Int) -> do
+          ReloadResult{..} <- liftIO r
+          when hasError $ print msgs
+          hasError `shouldBe` False
+          msgs     `shouldBe` ["hello:Mod"]
+          y  <- hello
+          x  `shouldNotBe` y
+          q2 <- level
+          q1 `shouldBe` q2
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,190 +1,2 @@
-{-# LANGUAGE DataKinds             #-}
-{-# LANGUAGE DeriveGeneric         #-}
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE OverloadedStrings     #-}
-{-# LANGUAGE RecordWildCards       #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-
-module Main where
-
-import           Control.Monad.Writer
-import           Data.List             (intercalate)
-import           Data.Text             (Text, pack, unpack)
-import           GHC.Generics
-import           Salak
-import           Salak.Internal
-import           Salak.Internal.Source
-import qualified Salak.Trie            as T
-import           System.Random         (randomIO)
-import           Test.Hspec
-import           Test.QuickCheck
-
-main :: IO ()
-main = hspec spec
-
-spec :: Spec
-spec = do
-  describe "Salak.Types" specProperty
-
-newtype SKey = SKey { unKey :: Text } deriving Show
-
-instance Arbitrary SKey where
-  arbitrary = do
-    key <- choose (1,20)
-    vs  <- vectorOf key $ do
-      k <- choose (1,20)
-      v <- vectorOf k $ choose ('a','z')
-      b <- choose (0,10) :: Gen Int
-      if b > 0 then return v else do
-        x <- choose (0,10) :: Gen Int
-        return (v ++ "[" ++ show x ++ "]")
-    return (SKey $ pack $ intercalate "." vs)
-
-data Hello = Hello
-  { hello :: IO Int
-  } deriving Generic
-
-instance MonadIO m => FromProp m Hello
-
-data Config = Config
-  { level :: IO Int
-  , world :: Maybe Bool
-  }
-
-instance MonadIO m => FromProp m Config where
-  fromProp = Config <$> "level" .?= (return 1) <*> "world"
-
-loadRandom :: (MonadThrow m, MonadIO m) => Text -> LoadSalakT m ()
-loadRandom key = loadList True (unpack key) go
-  where
-    go = do
-      a :: Int <- randomIO
-      return [(key, a)]
-
-specProperty :: SpecWith ()
-specProperty = do
-  context "selectors" $ do
-    it "normal" $ do
-      toKeys (""         :: Text) `shouldBe` Right (Keys $ [])
-      toKeys ("."        :: Text) `shouldBe` Right (Keys $ [])
-      toKeys (".."       :: Text) `shouldBe` Right (Keys $ [])
-      toKeys ("xx"       :: Text) `shouldBe` Right (Keys $ [KT "xx"])
-      toKeys ("xx[0]"    :: Text) `shouldBe` Right (Keys $ [KT "xx", KI 0])
-      toKeys ("xx.yy"    :: Text) `shouldBe` Right (Keys $ [KT "xx", KT "yy"])
-      toKeys ("xx[0][1]" :: Text) `shouldBe` Right (Keys $ [KT "xx", KI 0, KI 1])
-      show (Keys $ KT "x" : (KI <$> [0..9])) `shouldBe` "x[0][1][2][3][4][5][6][7][8][9]"
-    it "QuickCheck" $ do
-      quickCheck $ \s -> let s' = unKey s in (show <$> toKeys s') `shouldBe` Right (unpack s')
-  -- context "value" $ do
-  --   it "basic" $ do
-  --     newVT "xxxx"       0 `shouldBe` VT 0 "xxxx"
-  --     newVT "{x.y}"      0 `shouldBe` VT 0 "{x.y}"
-  --     newVT "${x*}"      0 `shouldBe` VT 0 "${x*}"
-      -- newVT "${x}"       0 `shouldBe` VRef 0 [RRef [KT "x"]]
-      -- newVT "${x.y}"     0 `shouldBe` VRef 0 [RRef [KT "x", KT "y"]]
-      -- newVT "${x${y}}"   0 `shouldBe` VT 0 "${x${y}}"
-      -- newVT "a${x}b"     0 `shouldBe` VRef 0 [RVal "a", RRef [KT "x"], RVal "b"]
-      -- newVT "a${x}b${"   0 `shouldBe` VRef 0 [RVal "a", RRef [KT "x"], RVal "b${"]
-      -- newVT "a${x}b${c}" 0 `shouldBe` VRef 0 [RVal "a", RRef [KT "x"], RVal "b", RRef [KT "c"]]
-  context "source" $ do
-    it "normal - 2" $ do
-      let (a,b,c) = extract T.empty $ gen 0 ([("hello", "world")] :: [(Text, Text)])
-      length c `shouldBe` 0
-      length (T.toList b) `shouldBe` 1
-  --   it "normal - 3" $ do
-  --     let (s2,e2) = runWriter $ insert "1"     (VT 0 "world") emptySource
-  --     sizeSource s2       `shouldBe` 1
-  --     length e2           `shouldBe` 0
-  --   it "normal - 4" $ do
-  --     let (s3,e3) = runWriter $ insert "a.b"   (VT 0 "world") emptySource
-  --     print s3
-  --     sizeSource s3       `shouldBe` 1
-  --     length e3           `shouldBe` 0
-  -- context "source - merge" $ do
-  --   let s  = fst $ runWriter $ insert "hello" (VT 0 "world") emptySource
-  --       so = fst $ runWriter $ insert "hello" (VT 1 "yyyyy") emptySource
-  --       s1 = fst $ runWriter $ insert "hello" (VT 0 "xxxxx") emptySource
-  --   it "merge - del" $ do
-  --     let (s2,e2) = runWriter $ replace 0 emptySource s
-  --     s2 `shouldBe` emptySource
-  --     e2 `shouldBe` ["#0 Del hello"]
-  --     let (s3,e3) = runWriter $ replace 1 emptySource s
-  --     s3 `shouldBe` s
-  --     e3 `shouldBe` []
-  --   it "merge - mod" $ do
-  --     let (s3,e3) = runWriter $ replace 0 s1 s
-  --     e3 `shouldBe` ["#0 Mod hello"]
-  --     s3 `shouldBe` s1
-  --     let (s2,e2) = runWriter $ replace 1 s1 s
-  --     e2 `shouldBe` []
-  --     s2 `shouldBe` s
-  --     let (_,e4) = runWriter $ replace 1 so s
-  --     e4 `shouldBe` ["#1 Add hello"]
-  --   it "merge - add" $ do
-  --     let (s4,e4) = runWriter $ replace 0 s emptySource
-  --     e4 `shouldBe` ["#0 Add hello"]
-  --     s4 `shouldBe` s
-  --     let (s2,e2) = runWriter $ replace 1 s emptySource
-  --     s2 `shouldBe` emptySource
-  --     e2 `shouldBe` []
-  --     let (s3,e3) = runWriter $ replace 1 so emptySource
-  --     e3 `shouldBe` ["#1 Add hello"]
-  --     s3 `shouldBe` so
-  --   it "merge - unchange" $ do
-  --     let (s5,e5) = runWriter $ replace 0 s s
-  --     e5 `shouldBe` []
-  --     s5 `shouldBe` s
-  -- context "Generic" $ do
-  --   it "conf" $ do
-  --     sp <- runLoadT Nothing $ loadOnceMock
-  --       [ ("name", "Daniel")
-  --       , ("age", "18")
-  --       , ("male", "yes")
-  --       ]
-  --     errs sp `shouldBe` []
-  --     let a = search "" sp :: Either String Conf
-  --     print a
-  --     isRight a `shouldBe` True
-  --   it "placeholder" $ do
-  --     let xs = [ ("name", "daniel")
-  --              , ("user", "${name}")
-  --              , ("a","${b}")
-  --              , ("b","${a}")
-  --              , ("x", "${y}")
-  --              , ("y", "${z}")
-  --              , ("z", "Hey! you")
-  --              ]
-  --     loadAndRunSalak (loadOnceMock xs) $ do
-  --       a <- require "name"
-  --       b <- require "user"
-  --       x <- require "x"
-  --       z <- require "z"
-  --       lift $ do
-  --         a `shouldBe` (b :: Text)
-  --         x `shouldBe` (z :: Text)
-  --     let x = loadAndRunSalak (loadOnceMock xs) (require "a") :: IO Text
-  --     x `shouldThrow` anyErrorCall
-  context "Reload test" $ do
-    it "reload" $ do
-      loadAndRunSalak (loadRandom "hello") $ do
-        Hello{..}  <- require ""
-        Config{..} <- require ""
-        x  <- liftIO hello
-        liftIO $ print x
-        liftIO $ print world
-        q1 <- liftIO level
-        r  <- askReload
-        lift $ quickCheck $ \(_ :: Int) -> do
-          ReloadResult{..} <- liftIO r
-          when hasError $ print msgs
-          hasError `shouldBe` False
-          msgs     `shouldBe` ["hello:Mod"]
-          y  <- hello
-          x  `shouldNotBe` y
-          q2 <- level
-          q1 `shouldBe` q2
-
-
-
+-- file test/Spec.hs
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
