In the following:
import Data.Bifunctor
import qualified Data.ByteString.Lazy.UTF8 as BLU
safeReadFile :: FilePath -> ExceptT Text IO Text
safeReadFile p = (lift $ doesFileExist p) >>= bool (throwError "File does not exist") (lift $ pack <$> readFile p)
safeDecodeJSONFile :: FromJSON a => Text -> FilePath -> ExceptT Text IO a
safeDecodeJSONFile t f = do
contents <- safeReadFile f
tryRight $ first (\x -> pack (x ++ (unpack t))) (eitherDecode (BLU.fromString (unpack contents)))
When I run runExceptT $ safeDecodeJSONFile "something" "nonExistantFile.json" I expect to get Left "Does not exist something" but instead I just get Left "Does not exist" - I know that the function I pass to first is being executed, since without the pack GHC complains that the type of (eitherDecode (BLU.fromString (unpack contents))) is ExceptT String IO a instead of ExceptT Text IO a - so why doesn't the concatenation from ++ also happen?
You've written
The
Monadinstance forExceptTgives up as soon as it hitsLeft, returning exactly that. So thetryRight ...never happens. You need to handle theLeftcase explicitly, perhaps usingcatchError.While we're at it, there's still a problem. You write
Unfortunately, this isn't reliable. First off, the file not existing is only one reason reading it can fail--there could be permission errors, network problems for networked filesystems, device errors if the file isn't a regular file, etc. Second, someone else could delete the file between the time you check its existence and the time you try to read it. The usual advice when trying to deal with files is not to check first. Just read the file and catch any exceptions using
catchor similar inControl.Exceptionor wrappers around them