web-dev-qa-db-ja.com

F#:可変と参照の比較

まず、この質問が重複する可能性があることを認めます。私に知らせて。

可変性が望まれる状況での一般的な「ベストプラクティス」とは何でしょうか。 F#はこのための2つの機能を提供しているようです。「ほとんど」の言語の変数のように機能するlet mutableバインディングと、使用するために明示的な逆参照が必要な参照セル(ref関数で作成)です。

どちらか一方に「強制」される場合がいくつかあります。NET相互運用機能は<-でミュータブルを使用する傾向があり、ワークフローの計算では:=refを使用する必要があります。したがって、これらのケースはかなり明確ですが、これらのシナリオの外で独自の可変変数を作成するときに何をすべきか知りたいです。あるスタイルが他のスタイルよりも優れている点は何ですか? (おそらく、実装についてのさらなる洞察が役立つでしょう。)

ありがとう!

79
J Cooper

私はgradbotが言ったことだけをサポートできます-突然変異が必要なとき、私はlet mutable

実装と2つの違いについて-refセルは基本的に、変更可能なレコードフィールドを含む非常に単純なレコードによって実装されます。あなたはそれらを自分で簡単に書くことができます:

type ref<'T> =  // '
  { mutable value : 'T } // '

// the ref function, ! and := operators look like this:
let (!) (a:ref<_>) = a.value
let (:=) (a:ref<_>) v = a.value <- v
let ref v = { value = v }

2つのアプローチの顕著な違いは、let mutableは(C#では可変変数として)可変値をスタックに格納し、refはヒープに割り当てられたレコードのフィールドに可変値を格納します。これはパフォーマンスに影響を与える可能性がありますが、数値はありません...

これにより、refを使用する可変値にエイリアスを設定できます。つまり、同じ可変値を参照する2つの値を作成できます。

let a = ref 5  // allocates a new record on the heap
let b = a      // b references the same record
b := 10        // modifies the value of 'a' as well!

let mutable a = 5 // mutable value on the stack
let mutable b = a // new mutable value initialized to current value of 'a'
b <- 10           // modifies the value of 'b' only!
128
Tomas Petricek

関連質問:「ローカルの変更可能な値はクロージャーによってキャプチャできないため、代わりにrefを使用する必要があると述べました。これは、変更可能なためです。クロージャでキャプチャされた値は、ヒープに割り当てる必要があります(クロージャはヒープに割り当てられるため)。 from F#ref-mutable vars vs object fields

let mutableは参照セルよりも優先されると思います。私は個人的に、必要なときにのみ参照セルを使用します。

私が書くほとんどのコードは、再帰呼び出しと末尾呼び出しのおかげで、可変変数を使用していません。変更可能なデータのグループがある場合は、レコードを使用します。オブジェクトの場合、私はlet mutableを使用してプライベートな可変変数を作成します。私は実際には、参照セルをクロージャー、通常はイベントにのみ使用しています。

18
gradbot

このMSDNブログの記事 のセクションで説明されているように、可変値の簡略化された使用法により、ラムダの参照セルが不要になりました。したがって、一般的には、それらはもはや必要ありません。

7
Andrii

この記事 Brianが答えを提供する可能性があります。

ミュータブルは使いやすく効率的(ラッピングなし)ですが、ラムダでキャプチャすることはできません。 Refセルはキャプチャできますがキャプチャされますが、冗長で効率が低下します(?-これは不明です)。

4
Mau

ウィキブックの Mutable Data セクションをご覧ください。

便宜上、関連する引用をいくつか示します。

Mutableキーワードは、レコードタイプで頻繁に使用され、変更可能なレコードを作成します

可変変数は多少制限されています。可変変数は、それらが定義されている関数のスコープ外ではアクセスできません。具体的には、これは別の関数のサブ関数で変更可能な変数を参照することが不可能であることを意味します。

Refセルは、可変変数の制限のいくつかを回避します。実際、参照セルは非常に単純なデータ型であり、レコード型の可変フィールドをラップします。

参照セルはヒープに割り当てられるため、複数の関数で共有できます。

3
danlei