Copying files in Haskell
One thing that I do not like very much is that the code calls
  doesDirectoryExist twice.


You can return the result of the doesDirectoryExist from getSubitems and pass it to copyItem, obviating the duplicate call.


  Especially, I would like to make it as succinct and as idiomatic as
  possible.


You can use low precedence &lt;$&gt; instead of fmap to remove some parentheses.

Also "." and ".." should be returned once from getDirectoryContents, so you can replace the

(filter (`notElem` [".", ".."])) 


with (\\ [".", ".."]).

Slight Behavior Difference between copyTree and copyTree'

Behavior of copyTree' is slightly different from copyTree, in that it will accept files as well as directories as parameter s. This is due to the fact that getSubitems' includes the input parameter (path, root of the subtree) in the descendants list it returns. You can get back the previous behavior by ignoring the first value returning from the getSubitems' in copyTree'. But I left the change in copyTree' as is for a behavior more consistent with cp -R of POSIX.

Modified Code

import Data.Functor ((&lt;$&gt;))
import Data.List ((\\))

getSubitems' :: FilePath -&gt; IO [(Bool, FilePath)]
getSubitems' path = getSubitemsRec ""
  where
    getChildren path =  (\\ [".", ".."]) &lt;$&gt; getDirectoryContents path

    getSubitemsRec relPath = do
        let absPath = path &lt;/&gt; relPath
        isDir &lt;- doesDirectoryExist absPath
        children &lt;- if isDir then getChildren absPath else return []
        let relChildren = [relPath &lt;/&gt; p | p &lt;- children]
        ((isDir, relPath) :) . concat &lt;$&gt; mapM getSubitemsRec relChildren

copyItem' baseSourcePath baseTargetPath (isDir, relativePath) = do
    let sourcePath = baseSourcePath &lt;/&gt; relativePath
    let targetPath = baseTargetPath &lt;/&gt; relativePath

    putStrLn $ "Copying " ++ sourcePath ++ " to " ++ targetPath
    if isDir
      then createDirectoryIfMissing False targetPath
      else copyFile sourcePath targetPath

copyTree' s t = do
    createDirectoryIfMissing True t
    subItems &lt;- getSubitems' s
    mapM_ (copyItem' s t) subItems