在 F# 中:如何获取目录中的文件名列表;预期单位有字符串

In F#: How do I obtain a list of the filenames in a directory; expected unit have string

我刚刚开始使用 F#,所以我想我会尝试一些简单的任务。

这列出了目录中 xml 个文件的完整路径:

System.IO.Directory.GetFiles("c:\tmp", "*.xml")
|> Array.iter (printfn "%s")

但我只想要文件名,所以我尝试了:

System.IO.Directory.GetFiles("c:\tmp", "*.xml")
|> Array.iter (System.IO.Path.GetFileName)
|> (printfn "%s")

这不会编译。它给出了错误:

这个表达式应该有类型 单位
但这里有类型 字符串

我搜索了示例,但找不到任何内容。我显然遗漏了一些简单而基本的东西,但是什么?

由于您是新手,因此更容易修复错误的一件事是考虑像数学语句这样的语句,这些语句可以由更简单的函数构建,但也可以分解。

因此,通过分解您的问题,您可以获得更容易解决的更细粒度的错误。

System.IO.Directory.GetFiles("c:\tmp", "*.xml")
|> Array.iter (System.IO.Path.GetFileName)
|> (printfn "%s")

分解为

let directoryArray = System.IO.Directory.GetFiles("c:\tmp", "*.xml")
let nameArray = Array.iter (System.IO.Path.GetFileName) directoryArray
(printfn "%s") nameArray 

现在错误应该更容易理解了

如果我们查看 Array.iter 的签名,即 iter : ('T -> unit) -> 'T [] -> unit,我们会发现它需要一个函数 ('T -> unit) 接受一个类型并且 return 是一个 unit 这意味着 return 什么都没有,在这种情况下打印会起作用,但是您不想 return 什么都不想将目录数组转换为文件名数组。所以 Array.iter 将不起作用,您需要一个数组函数,该函数将一个函数应用于数组中的每个项目,并且 return 是一个新的 ArrayArray.map 执行此操作 map : ('T -> 'U) -> 'T [] -> 'U [] 为了更好地理解数组函数并了解它们的工作原理,可以添加 lambda function.

同样(printfn "%s");可以添加一个 lambda 函数来传入一个值。

let directoryArray = System.IO.Directory.GetFiles("c:\tmp", "*.xml")
let nameArray = Array.map (fun x -> (Path.GetFileName(x))) directoryArray
Array.iter (fun x -> printfn "%s" x) nameArray

现在我们可以使用 |>

来简化语句
System.IO.Directory.GetFiles("c:\tmp", "*.xml")
|> Array.map (fun x -> (Path.GetFileName(x)))
|> Array.iter (fun x -> printfn "%s" x)

并通过删除 lambdas

再次简化
open System.IO

Directory.GetFiles("c:\tmp", "*.xml") 
|> Array.map Path.GetFileName 
|> Array.iter (printfn "%s")