如果文件不存在,您最好删除文件并简单地恢复:
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
这避免了有人在您的代码检查文件是否存在和删除文件之间删除文件的竞争条件。在您的情况下这可能无关紧要,但无论如何这是一个好习惯。
注意import Prelude hiding (catch) 行——这是因为 Prelude 包含来自异常处理的旧函数,现在已弃用这些函数,取而代之的是 Control.Exception,它还有一个名为 catch 的函数;导入行只是隐藏了 Prelude 的 catch 以支持 Control.Exception。
但是,这仍然留下了您更基本的潜在问题:您如何在IO 中编写条件语句?
好吧,在这种情况下,只需这样做就足够了
when fileExists $ removeFile filename
(使用Control.Monad.when)。但是在这里查看类型很有帮助,就像在 Haskell 中通常一样。
条件的两个分支必须具有相同的类型。所以要填写
if fileExists
then removeFile filename
else ???
我们应该看看removeFile filename的类型;无论??? 是什么,它都必须具有相同的类型。
System.Directory.removeFile 的类型为 FilePath -> IO (),因此 removeFile filename 的类型为 IO ()。所以我们想要的是一个 IO 操作,其结果类型为 (),它什么都不做。
好吧,return 的目的是构造一个没有效果的动作,只返回一个常量值,而return () 具有正确的类型:IO ()(或更一般地说,(Monad m) => m () )。所以??? 是return ()(你可以看到我在上面改进的sn-p 中使用了它,当removeFile 因为文件不存在而失败时什么都不做)。
(顺便说一句,您现在应该可以在return () 的帮助下实现when;这真的很简单:))
如果您一开始很难进入 Haskell 的工作方式,请不要担心 - 它会及时自然而然地出现,当它进入时,它会非常有益。 :)