我发现自己在haskell中做了越来越多的脚本.但在某些情况下,我真的不确定如何"正确"地做到这一点.
例如,递归地复制目录(la unix cp -r).
由于我主要使用Linux和Mac Os,我通常作弊:
import System.Cmd
import System.Exit
copyDir :: FilePath -> FilePath -> IO ExitCode
copyDir src dest = system $ "cp -r " ++ src ++ " " ++ dest
Run Code Online (Sandbox Code Playgroud)
但是,以独立于平台的方式复制目录的推荐方法是什么?
我没有找到任何适合hackage的东西.
这是我到目前为止使用的相当天真的实现:
import System.Directory
import System.FilePath((</>))
import Control.Applicative((<$>))
import Control.Exception(throw)
import Control.Monad(when,forM_)
copyDir :: FilePath -> FilePath -> IO ()
copyDir src dst = do
whenM (not <$> doesDirectoryExist src) $
throw (userError "source does not exist")
whenM (doesFileOrDirectoryExist dst) $
throw (userError "destination already exists")
createDirectory dst
content <- getDirectoryContents src
let xs = filter (`notElem` [".", ".."]) content
forM_ xs $ \name -> do
let srcPath = src </> name
let dstPath = dst </> name
isDirectory <- doesDirectoryExist srcPath
if isDirectory
then copyDir srcPath dstPath
else copyFile srcPath dstPath
where
doesFileOrDirectoryExist x = orM [doesDirectoryExist x, doesFileExist x]
orM xs = or <$> sequence xs
whenM s r = s >>= flip when r
Run Code Online (Sandbox Code Playgroud)
有什么方法可以做到这一点吗?
我用hammar和FUZxxl的建议更新了这个.
......但是对于这样一个共同的任务,我仍然感觉有些笨拙!
cp_r "sourcedir" "targetdir"
Run Code Online (Sandbox Code Playgroud)
Shelly首先尝试使用原生(cp -r如果可用).如果没有,它将回退到本机Haskell IO实现.
有关的类型语义的详细信息cp_r,请参阅这篇文章是我写的来描述了如何使用cp_r与String和或Text.
我在 Hackage 上找不到任何可以做到这一点的东西。
你的代码对我来说看起来很不错。一些评论:
Run Code Online (Sandbox Code Playgroud)dstExists <- doesDirectoryExist dst
这没有考虑到可能存在具有目标名称的文件。
Run Code Online (Sandbox Code Playgroud)if or [not srcExists, dstExists] then print "cannot copy"
您可能想要引发异常或返回状态,而不是直接从此函数打印。
Run Code Online (Sandbox Code Playgroud)paths <- forM xs $ \name -> do [...] return ()
由于您没有使用paths任何东西,因此可以将其更改为
forM_ xs $ \name -> do
[...]
Run Code Online (Sandbox Code Playgroud)