Search code examples
haskellconditional-statementspredicateio-monad

What is the idiomatic Haskell-way to act on predicates in IO?


For some file operation, I need to check if the file exists, if it has been modified, and only then perform some operation on it. My newbie Haskell code looks as follows (simplified):

someFileOp ::FileContents -> FilePath -> IO (FileOpResult)
someFileOp contents absFilePath = do
    fileExists <- DIR.doesFileExist absFilePath
    if fileExists
        then do
            isMod <- isModified contents absFilePath
            if isMod
                then return FileModified
            else return $ doSomethingWithFile
        else return FileNotFound

It does work. However, the nested if-expressions look wrong to me - not FP-like. What would be an idiomatic way to check several Boolean conditions in IO and then take some action depending on their result?


Solution

  • The code you posted looks fine to me. Another possibility would be to act in a short-circuiting monad like ExceptT Err IO.

    data Err = FileNotFound | FileModified
    
    getFileContents :: FilePath -> ExceptT Err IO FileContents
    getFileContents fp = do
        exists <- doesFileExist fp
        if exists then {- ... -} else throwError FileNotFound
    
    someFileOp :: FileContents -> FilePath -> ExceptT Err IO FileOpResult
    someFileOp fc fp = do
        fc' <- getFileContents fp
        when (fc /= fc') (throwError FileModified)
        doSomethingWithFile