F# 查找最近 5 天内修改过的子目录中的所有文件

F# Find all files in subdirectories modified within the last 5 days

我对 F# 还很陌生,所以请多关照。我正在尝试以函数式风格编写代码,以查看过去 5 天内修改的所有文件的目录(和子目录),然后对这些文件执行某些操作(目前只是将名称写入控制台) .

我的代码是:

open System.IO

let rec getAllFiles dir pattern =
    seq { yield! Directory.EnumerateFiles(dir, pattern)
          for d in Directory.EnumerateDirectories(dir) do
              yield! getAllFiles d pattern }

let printMe x = printfn "%A" x

let hasChangedRecently fileName =
    let myFile = System.IO.FileInfo(fileName)
    let f myFile = function
    | myFile when myFile.LastWriteTime >= System.DateTime.Parse "10-04-2015" -> printMe MyFile.Name
    | _ -> ()

    f fileName

[<EntryPoint>]
let main argv =
    getAllFiles @"c:\temp" "*.xml"
    |> Seq.iter hasChangedRecently

    System.Console.ReadKey() |> ignore
    0 // return an integer exit code

hasChangedRecently 块中的一切都出错了。

错误是:

myFile.LastWriteTime
Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.

MyFile.Name
The namespace or module 'MyFile' is not defined

|> Seq.iter hasChangedRecently
Type mismatch. Expecting a
string -> unit    
but given a
string -> 'a -> unit    
The type 'unit' does not match the type ''a -> unit'

我很确定这些是基本错误,但非常感谢您的指导。

我会将 hasRecentlyChanged 更改为 string -> bool 函数并使用它过滤文件,然后使用单独的函数来打印文件。

let hasChangedRecently fileName =
    let myFile = System.IO.FileInfo(fileName)
    myFile.LastWriteTime >= System.DateTime.Parse "10-04-2015"

let printFile file =
    printfn "%s" file

并在 main 中:

getAllFiles @"c:\temp" "*.xml"
|> Seq.filter hasChangedRecently
|> Seq.iter printFile

此外,如果需要,您可以通过使用 .NET 中内置的 SearchOption.AllDirectories 来避免 getAllFiles 递归:

Directory.EnumerateFiles(dir, pattern, SearchOption.AllDirectories)

我想你也可以像那样重写hasChangedRecently(并让它打印结果)

let hasChangedRecently fileName =
    match  System.IO.FileInfo(fileName) with
    | myFile when myFile.LastWriteTime >= System.DateTime.Parse "10-04-2015" -> printfn "%s" myFile.Name
    | _ -> ()

如果你想使用函数,你必须以某种方式帮助编译器推断类型。在这种情况下你可以这样写:

let hasChangedRecently fileName =
    let analyze: (System.IO.FileInfo -> _) = 
        function 
        | x when x.LastAccessTime > System.DateTime.Parse "10-04-2015" -> printfn "%s" x.Name 
        | _ -> ()
    analyze System.IO.FileInfo(fileName)

正如 Vandroiy 在他的评论中很好地解释的那样,function 对未命名的参数进行模式匹配。这里我们只是将 analyze 的类型定义为一个函数,它在参数中接受一个 FileInfo 并返回任何内容。