What is the right way of doing this in Haskell?
if exists "foo.txt" then delete "foo.txt" doSomethingElse
So far I have:
import System.Directory main = do filename <- getFileNameSomehow fileExists <- doesFileExist filename if fileExists then removeFile filename ??? doSomethingElse
Well, it's entirely impossible to remove a file that doesn't exist, so it seems that the concept of "delete a file only if it exists" is redundant. So, rm -f filename , or rm filename 2>> /dev/null , or [[ -r filename ]] && rm filename would be some options..
You can apply the 'rm' command to remove an existing file. In the following script, an empty file is created by using the 'touch' command to test 'rm' command. Next, 'rm' command is used to remove the file, test.
To delete a file if exists in Python, use the os. path. exists() and os. remove() method.
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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With