exception NoDirectory of string
let dir = DirectoryInfo "c:\\"
let dirExists (dir: DirectoryInfo): bool = dir.Exists
let rec getFiles (dir: DirectoryInfo) : FileInfo[] =
let subs =
match dirExists dir with
| true -> dir.GetDirectories ""
| false -> raise (NoDirectory("error"))
subs
|> Array.map (fun (dir: DirectoryInfo) -> getFiles dir)
|> Array.reduce (fun acc elem -> acc.append elem) List.empty
因此,我尝试将FileInfo[][]
简化为FileInfo[]
或更准确地将FileInfo[][]
缩减为List<FileInfo>
。
我认为因为管道只适用于一元函数,所以这意味着函数可以调整Array.reduce
,但我有点卡在那里,例如:
let unaryReduce (fileInfoArray: FileInfo[]) = Array.reduce (fun acc elem -> acc.append elem) List.empty
我是对的吗?靠近......很远......
经过一些修改后我得到了这个:
let dir = DirectoryInfo "c:\\"
let dirExists (dir: DirectoryInfo): bool = dir.Exists
let getFiles (dir: DirectoryInfo) : FileInfo[] = dir.GetFiles ""
let rec recursiveGetFiles (dir: DirectoryInfo) : FileInfo[] =
let subs =
match dirExists dir with
| true -> dir.GetDirectories ""
| false -> raise (NoDirectory("error"))
subs
|> Array.collect (fun (dir: DirectoryInfo) -> recursiveGetFiles dir)
|> Array.concat<FileInfo[]> getFiles <| dir
我昨天才开始看F#,我想尝试使用烟斗。我得到的错误是在最后一行:
此表达式应具有类型
FileInfo [] - &gt; &#39; a - &gt; FileInfo []
但这里有类型FileInfo [] []
这告诉我,collect
并未正确使用以展平数组......
答案 0 :(得分:2)
如果你想使用流水线技术,这样的事情应该有效:
exception NoDirectory of string
// DirectoryInfo -> bool
let dirExists (dir: DirectoryInfo) = dir.Exists
// DirectoryInfo -> FileInfo []
let getFiles (dir: DirectoryInfo) = dir.GetFiles "."
// DirectoryInfo -> FileInfo []
let rec recursiveGetFiles dir =
match dirExists dir with
| true -> dir.GetDirectories "."
| false -> raise (NoDirectory "error")
|> Array.collect recursiveGetFiles
|> Array.append (getFiles dir)
我不建议抛出此处所示的异常,但我保留了这一部分,以使其尽可能接近OP。但是,一旦您熟悉了F#和函数式编程的基础知识,就应该了解使用Either monad的函数错误处理。一个好的起点是:http://fsharpforfunandprofit.com/rop
答案 1 :(得分:1)
您从编辑中获得的错误来自后面管道的优先级(&lt; |)a |> f <| b
被视为(a |> f) <| b
当您想要的是a |> (f <| b)
时,a |> (f b)
只是let getAllFiles (dir: DirectoryInfo) =
let rec aux dir = [
for file in getFiles dir -> file
for subDir in getDirs dir do yield! aux subDir
]
if dirExists dir
then aux dir
else raise <| NoDirectory "error"
1}} (如Mark Seemann's answer中所示)
那说你可以用这种方式写一些东西(IMO):
list
这样我们将递归部分与检查部分分开
递归部分更简单,更易读,最初返回getDirs
而不是数组(我添加了if
)
检查部分由true/false
完成,因为getDirs
的匹配不会在此处添加值
并且仅针对初始参数完成,因为let rec getAllFiles (dir: DirectoryInfo) = [
if dirExists dir then
for file in getFiles dir -> file
for subDir in getDirs dir do yield! getAllFiles subDir
]
很少有机会返回不存在的目录*
*即使有人在错误的时间删除了一个,但在这种情况下你可以重写它
{{1}}
这样你甚至不需要提出错误,只需获得一个不存在的目录的空列表。
答案 2 :(得分:0)
如果你需要seq,你也可以使用EnumarateDirectories
,虽然使用IO我会小心使用延迟集合。这将返回我在项目(子)目录中的所有56个文件:
open System.IO
let dir = DirectoryInfo __SOURCE_DIRECTORY__
dir.GetDirectories("*",SearchOption.AllDirectories) |> Array.collect (fun x -> x.GetFileSystemInfos())
如果用Array.collect
替换Array.map
,则顶级集合将是目录的集合(正好是我所拥有的5)。