Remove file if it exists

前端 未结 2 1841
遇见更好的自我
遇见更好的自我 2021-02-05 02:49

What is the right way of doing this in Haskell?

if exists \"foo.txt\" then delete \"foo.txt\"
doSomethingElse

So far I have:

im         


        
2条回答
  •  耶瑟儿~
    2021-02-05 03:22

    You would be better off removing the file and simply recovering if it does not exist:

    import Prelude hiding (catch)
    import System.Directory
    import Control.Exception
    import System.IO.Error hiding (catch)
    
    removeIfExists :: FilePath -> IO ()
    removeIfExists fileName = removeFile fileName `catch` handleExists
      where handleExists e
              | isDoesNotExistError e = return ()
              | otherwise = throwIO e
    

    This avoids the race condition of someone deleting the file between your code checking whether it exists and deletes it. It might not matter in your case, but it's good practice anyway.

    Note the import Prelude hiding (catch) line — this is because the Prelude contains older functions from exception handling which are now deprecated in favour of Control.Exception, which also has a function named catch; the import line simply hides the Prelude's catch in favour of Control.Exception's.

    However, that still leaves your more fundamental underlying question: how do you write conditionals in IO?

    Well, in this case, it would suffice to simply do

    when fileExists $ removeFile filename
    

    (using Control.Monad.when). But it's helpful here, as it usually is in Haskell, to look at the types.

    Both branches of a conditional must have the same type. So to fill in

    if fileExists
        then removeFile filename
        else ???
    

    we should look at the type of removeFile filename; whatever ??? is, it has to have the same type.

    System.Directory.removeFile has the type FilePath -> IO (), so removeFile filename has the type IO (). So what we want is an IO action with a result of type () that does nothing.

    Well, the purpose of return is to construct an action that has no effects, and just returns a constant value, and return () has the right type for this: IO () (or more generally, (Monad m) => m ()). So ??? is return () (which you can see I used in my improved snippet above, to do nothing when removeFile fails because the file doesn't exist).

    (By the way, you should now be able to implement when with the help of return (); it's really simple :))

    Don't worry if you find it hard to get into the Haskell way of things at first — it'll come naturally in time, and when it does, it's very rewarding. :)

提交回复
热议问题