I recently watched a video in which the speaker said that Haskell is not suited for real-world tasks, such as copying files from one folder to another. So I tried to write a program that copies a given file system tree to a new location. The usage of the program is
copy_tree <source path> <target path>
If the target path does not exists, it is created. Then all folders and files under <source path>
are copied to <target path>
. Here is my copy_tree.hs
source. I would like to have feedback and suggestions on how to improve it. Especially, I would like to make it as succinct and as idiomatic as possible.
One thing that I do not like very much is that the code calls doesDirectoryExist
twice.
import System.Directory
import System.Environment
import System.FilePath
getSubitems path = getSubitemsRec ""
where
getChildren path = do
isDir <- doesDirectoryExist path
if isDir
then fmap (filter (`notElem` [".", ".."])) (getDirectoryContents path)
else return []
getSubitemsRec relPath = do
children <- getChildren (path </> relPath)
let relChildren = [relPath </> p | p <- children]
nephewItems <- mapM getSubitemsRec relChildren
return (relChildren ++ (concat nephewItems))
copyItem baseSourcePath baseTargetPath relativePath = do
let sourcePath = baseSourcePath </> relativePath
let targetPath = baseTargetPath </> relativePath
putStrLn $ "Copying " ++ sourcePath ++ " to " ++ targetPath
isDir <- doesDirectoryExist sourcePath
if isDir
then createDirectoryIfMissing False targetPath
else copyFile sourcePath targetPath
copyTree s t = do
subItems <- getSubitems s
createDirectoryIfMissing True t
mapM_ (copyItem s t) subItems
main = do
args <- getArgs
if (length args) == 2
then copyTree (args !! 0) (args !! 1)
else putStrLn "Usage: copy_tree <source> <target>"