n't use decodeFileEither
                                -- decodeFileEither full_path
                                (liftM Yaml.decodeEither' $ B.readFile full_path)

                return $ case ioerr_or_v of
                            Left ioe          -> Left $ Left ioe
                            Right (Left perr) -> Left $ Right $ YamlFileParseException full_path perr
                            Right (Right x)   -> Right x

        first_try <- try_dir $ LNE.head base_dir_list
        case first_try of
            Right v         -> return $ Right v
            Left first_err  -> do
                let is_does_not_exist_err (Left ioe) = isDoesNotExistError ioe
                    is_does_not_exist_err (Right _)  = False
                let go []       last_err    = either (liftIO . throwIO) (return . Left) last_err
                    go (x:xs)   last_err    = do
                        try_dir x
                            >>= either
                                    (\e -> go xs $ if is_does_not_exist_err last_err then e else last_err)
                                    (return . Right)

                go (LNE.tail base_dir_list) first_err

-- | May throw IOError
runDelayedYamlLoaderL_IOE :: (MonadIO m) =>
    NonEmpty FilePath    -- ^ 消息文件存放目录
    -> DelayedYamlLoader a
    -> m (Either YamlFileParseException a)
runDelayedYamlLoaderL_IOE base_dirs f = liftIO $ runReaderT f base_dirs

runDelayedYamlLoaderL :: (MonadIO m) =>
    NonEmpty FilePath    -- ^ 消息文件存放目录
    -> DelayedYamlLoader a
    -> m (Either String a)
runDelayedYamlLoaderL base_dir_list get_ext = liftIO $ do
    err_or_x <- tryIOError $ runReaderT get_ext base_dir_list
    case err_or_x of
       
mkDelayedYamlLoader :: forall a. FromJSON a => FilePath -> DelayedYamlLoader a
mkDelayedYamlLoader fp = do
    base_dir_list <- ask
    liftIO $ do
        -- 运行时，如果全部都有 IOError，抛出第一个非 DoesNotExistError
        let try_dir :: FilePath -> IO (Either (Either IOError YamlFileParseException) a)
            try_dir bp = do
                let full_path = bp </> fp
                ioerr_or_v <- tryIOError $ do
                                -- we need to catch IOError, so don't use decodeFileEither
                                -- decodeFileEither full_path
                                (liftM Yaml.decodeEither' $ B.readFile full_path)

                return $ case ioerr_or_v of
                            Left ioe          -> Left $ Left ioe
                            Right (Left perr) -> Left $ Right $ YamlFileParseException full_path perr
                            Right (Right x)   -> Right x

        first_try <- try_dir $ LNE.head base_dir_list
        case first_try of
            Right v         -> return $ Right v
            Left first_err  -> do
                let is_does_not_exist_err (Left ioe) = isDoesNotExistError ioe
                    is_does_not_exist_err (Right _)  = False
                let go []       last_err    = either (liftIO . throwIO) (return . Left) last_err
                    go (x:xs)   last_err    = do
                        try_dir x
                            >>= either
                                    (\e -> go xs $ if is_does_not_exist_err last_err then e else last_err)
                                    (return . Right)

                go (LNE.tail base_dir_list) first_err

-- | May throw IOError
mkDelayedYamlLoader fp = do
    base_dir_list <- ask
    liftIO $ do
        -- 运行时，如果全部都有 IOError，抛出第一个非 DoesNotExistError
        let try_dir :: FilePath -> IO (Either (Either IOError YamlFileParseException) a)
            try_dir bp = do
                let full_path = bp </> fp
                ioerr_or_v <- tryIOError $ do
                                -- we need to catch IOError, so don't use decodeFileEither
                                -- decodeFileEither full_path
                                (liftM Yaml.decodeEither' $ B.readFile full_path)

                return $ case ioerr_or_v of
                            Left ioe          -> Left $ Left ioe
                            Right (Left perr) -> Left $ Right $ YamlFileParseException full_path perr
                            Right (Right x)   -> Right x

        first_try <- try_dir $ LNE.head base_dir_list
        case first_try of
            Right v         -> return $ Right v
            Left first_err  -> do
                let is_does_not_exist_err (Left ioe) = isDoesNotExistError ioe
                    is_does_not_exist_err (Right _)  = False
                let go []       last_err    = either (liftIO . throwIO) (return . Left) last_err
                    go (x:xs)   last_err    = do
                        try_dir x
                            >>= either
                                    (\e -> go xs $ if is_does_not_exist_err last_err then e else last_err)
                                    (return . Right)

                go (LNE.tail base_dir_list) first_err

-- | May throw IOError