0

ディレクトリ内のすべてのファイルに関数 B を適用する、これに似た関数 A があります。各ファイルには一定数の「エントリ」があります。関数 B は、現在のエントリの合計をパラメータとして取り、現在のファイルで見つかった新しいエントリの数を返します。

また、処理されたファイルの数をカウントし、ファイルが処理されるたびにこのカウントを表示する必要があります。私の必須のバックグラウンドにより、2 つの変更可能な変数と for ループを思い付きました。

let files = Directory.EnumerateFiles sourceDirectory
let mutable numEntries = 0
let mutable numFiles = Seq.length files
let mutable index = 0
for file in files do
     printfn "done %d of %d" index numFiles
     let numNewEntries = processFile file numEntries
     numEntries <- numEntries + numNewEntries
     index <- index + 1

それで、いくつか質問があります:

  • これをより慣用的で機能的なスタイルで書くにはどうすればよいですか?
  • より慣用的なソリューションの利点を説明できますか? 私は関数型プログラミングに非常に慣れていないため、ループの汚い命令の何が問題なのかがわからないことがあります。
4

2 に答える 2

6

より機能的な例を次に示します。

let files = Directory.EnumerateFiles sourceDirectory
let numFiles = Seq.length files
files 
|> Seq.mapi (fun idx file -> (idx,file)) // Get access to the index in a loop
|> Seq.fold (fun numentries (index,file) ->
         printfn "done %d of %d" index numFiles
         numentries + (processFile file numFiles)
         ) 0

を使用するmapiことで、ループ内のインデックスにアクセスできるようになり、最初の可変変数が削除されます。fold2つ目は、可変変数ではなくファイルの総数を追跡するためにを使用することで排除されます。

これの主な利点は、変更可能な状態がなくても、コードを複数のスレッドで実行するように簡単に変換できることです。また、変数は定数であるため、コードについて推論するのが簡単になります。

于 2012-07-25T01:05:17.533 に答える
1

あなたが最終的に求めているのは の最終値であると仮定するとnumEntries、ここに私の見解があります:

let getNumEntries sourceDirectory =
    Directory.GetFiles sourceDirectory
    |> fun files -> (0, 0, files.Length), files
    ||> Array.fold (fun (index, numEntries, numFiles) file ->
        printfn "done %d of %d" index numFiles
        index + 1, numEntries + processFile file numEntries, numFiles)
    |> fun (_,numEntries,_) -> numEntries

processFile最終値ではなく副作用だけを求めている場合はnumEntries、 に置き換えfun (_,numEntries,_) -> numEntriesますignore


より慣用的なソリューションの利点を説明できますか? 私は関数型プログラミングに非常に慣れていないため、ループの汚い命令の何が問題なのかわからなくなることがあります。

主観的であることに加えて、それはかなり広く、他の複数の回答で私がここでできるよりもはるかに徹底的に回答されています.

于 2012-07-25T02:35:32.697 に答える