什么是haskell复制目录的方法

oli*_*ver 15 haskell

我发现自己在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的建议更新了这个.
......但是对于这样一个共同的任务,我仍然感觉有些笨拙!

Uli*_*ler 5

可以使用Shelly库来执行此操作,请参阅cp_r:

cp_r "sourcedir" "targetdir"
Run Code Online (Sandbox Code Playgroud)

Shelly首先尝试使用原生(cp -r如果可用).如果没有,它将回退到本机Haskell IO实现.

有关的类型语义的详细信息cp_r,请参阅这篇文章是我写的来描述了如何使用cp_rString和或Text.


ham*_*mar 4

我在 Hackage 上找不到任何可以做到这一点的东西。

你的代码对我来说看起来很不错。一些评论:

  1. dstExists <- doesDirectoryExist dst
    
    Run Code Online (Sandbox Code Playgroud)

    这没有考虑到可能存在具有目标名称的文件。

  2. if or [not srcExists, dstExists] then print "cannot copy"
    
    Run Code Online (Sandbox Code Playgroud)

    您可能想要引发异常或返回状态,而不是直接从此函数打印。

  3. paths <- forM xs $ \name -> do
        [...]
      return ()
    
    Run Code Online (Sandbox Code Playgroud)

    由于您没有使用paths任何东西,因此可以将其更改为

    forM_ xs $ \name -> do
      [...]
    
    Run Code Online (Sandbox Code Playgroud)