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 [] -> 'a -> FileInfo [] 但这里有类型 FileInfo
这告诉我,collect没有被正确的使用来扁平数组.
发布于 2016-10-08 12:23:27
如果您想要使用管道,这样的东西应该可以工作:
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#和函数式编程的基础知识,您就应该了解使用任一单块处理函数错误的方法。这里是一个很好的起点:http://fsharpforfunandprofit.com/rop
发布于 2016-10-08 12:54:08
从编辑中得到的错误来自back管道的优先级(<\\),当您想要的是a |> f <| b时,(a |> f) <| b被看作是a |> (f <| b),它只是a |> (f b) (如在https://stackoverflow.com/a/39932313/4925216中所示)。
也就是说,你可以用这样的方式写些更易读的东西:
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"这样,我们将递归部分与检查部分分离开来。
递归部分更简单、更易读,并且返回一个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
]这样,您甚至不需要引发错误,只需为一个不存在的目录获得一个空列表即可。
发布于 2016-10-08 02:17:45
如果需要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,则顶级集合将是目录的集合(与我所拥有的完全相同)。
https://stackoverflow.com/questions/39927484
复制相似问题