Recursively traverse directory tree and print all files
let allFiles' = Seq.append allFiles files
let allFiles'' = dirs |&gt; Seq.map (traverse allFiles') |&gt; Seq.concat


Just because you can use ' to differentiate variables does not mean that you should. Unless it's very clear what the different variables mean, you should use separate name for each of them.



dirs |&gt; Seq.map (traverse allFiles') |&gt; Seq.concat


You can simplify Seq.map followed by Seq.concat to just Seq.collect:

dirs |&gt; Seq.collect (traverse allFiles')




let rec traverse allFiles dir =
    let dirs,files = getDirObjects dir
    let allFiles' = Seq.append allFiles files
    let allFiles'' = dirs |&gt; Seq.map (traverse allFiles') |&gt; Seq.concat
    Seq.append allFiles' allFiles''


This code is wrong. You pass files from the parent directory to each child directory and then return the parent directory files from each child directory and concat them.

For example, if you had two subdirectories, dir1 and dir2 and two files, file-in-root and dir1/file-in-dir1, then your code outputs:

file-in-root
file-in-root
file-in-root
dir2/file-in-dir2


Notice how file-in-root is output three times: once for the root directory, and also once for each subdirectory.

The solution here is not to pass allFiles to traverse:

let rec traverse dir =
    let dirs,files = getDirObjects dir
    let filesInDirs = dirs |&gt; Seq.collect traverse
    Seq.append files filesInDirs




let dirs = dir.GetDirectories()
let files = dir.GetFiles()


Since you're using lazy seqs extensively, it would make sense to make dirs and files lazy seqs too, by using seq-returning Enumerate* methods instead of array-returning Get* methods. This way, if you enumerate the resulting seq only partially, it's going to be more efficient.

let dirs = dir.EnumerateDirectories()
let files = dir.EnumerateFiles()