F# の値は不変であると読みました。しかし、値の定義を再定義するという概念にも出くわしました。これは、以前のものに影を落としています。これは変更可能な値とどう違うのですか? これは単なる理論上の構成要素としてではなく、変更可能な値をいつ使用し、代わりにいつ式を再定義するかについてアドバイスがあればお願いします。または、後者が慣用的な f# ではないことを誰かが指摘できる場合。
再定義の基本的な例:
let a = 1;;
a;; //1
let a = 2;;
a;; //2
更新 1:
以下の回答に加えて、最上位レベルの Fsharp インタラクティブでの再定義は、異なる終端でのみ許可されます。以下は fsi でも同様にエラーになります:
let a = 1
let a = 2;;
Error: Duplicate definition of value 'a'
一方、let バインディングでは再定義が可能です。
更新 2: 実質的な違い、クロージャーは変更可能な変数では機能しません:
let f =
let mutable a = 1
let g () = a //error
0
f;;
更新 3:
参照を使用して副作用をモデル化できますが、たとえば:
let f =
let a = ref 1
let g = a
a:=2
let x = !g + !a
printfn "x: %i" x //4
f;;
再定義と変更可能なキーワードの使用の実際的な違いは、クロージャーでの使用方法の違いに加えて、まったくわかりません。たとえば、次のようになります。
let f =
let a = 1
let g = a
let a = 2
let x = g + a
printfn "x: %i" x //3
f;;
対
let f =
let mutable a = 1
let g = a
a <-2
let x = g + a
printfn "x: %i" x //3
f;;
別の考え: スレッドの操作方法がわかりませんが、(a) 別のスレッドが let バインディング内の可変変数の値を変更できるか、(b) 別のスレッドが a 内の値の名前を再バインド/再定義できるか束縛させます。私は確かにここに何かが欠けています。
更新 4: 最後のケースの違いは、ネストされたスコープからミューテーションが引き続き発生するのに対し、ネストされたスコープでの再定義/再バインドは、外部スコープからの定義を「シャドウ」することです。
let f =
let mutable a = 1
let g = a
if true then
a <-2
let x = g + a
printfn "x: %i" x //3
f;;
対
let f =
let a = 1
let g = a
if true then
let a = 2
printfn "a: %i" a
let x = g + a
printfn "x: %i" x //2
f;;