Я читал, что значения в F # неизменяемы. Однако я также сталкивался с концепцией переопределения определений значений, которые затмевают предыдущие. Чем оно отличается от изменяемого значения? Я спрашиваю об этом не только как о теоретической конструкции, но и о том, есть ли какие-либо советы о том, когда использовать изменяемые значения, а когда вместо этого переопределять выражения; или если кто-то может указать, что последнее не является идиоматическим f #.
Базовый пример переопределения:
let a = 1;;
a;; //1
let a = 2;;
a;; //2
Обновление 1:
Добавляя к ответам ниже, переопределение в Fsharp interactive на верхнем уровне разрешено только в разных окончаниях. Следующее также вызовет ошибку в 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;;
Я не вижу практической разницы между переопределением и использованием ключевого слова mutable, помимо разницы в использовании с замыканиями, например:
let f =
let a = 1
let g = a
let a = 2
let x = g + a
printfn "x: %i" x //3
f;;
vs
let f =
let mutable a = 1
let g = a
a <-2
let x = g + a
printfn "x: %i" x //3
f;;
Еще одна мысль: я не уверен, как работать с потоками, но (а) может ли другой поток изменить значение изменяемой переменной в привязке let и (б) может другой поток повторно связать / переопределить имя значения внутри пусть привязка. Я определенно что-то здесь упускаю.
Обновление 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;;
vs
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;;