Неизменный в F#

Я знаю, что переменные в F# являются неизменяемыми по умолчанию. Но, например, в F# интерактив:

  > let x = 4;;

val x : int = 4

> let x = 5;;

val x : int = 5

> x;;
val it : int = 5
> 

Итак, я назначаю 4 х, затем 5 х, и это меняется. Это правильно? Должно ли это дать какую-то ошибку или предупреждение? Или я просто не понимаю, как это работает?

4 ответа

Решение

Когда ты пишешь let x = 3, вы привязываете идентификатор x к стоимости 3, Если вы делаете это второй раз в той же области, вы объявляете новый идентификатор, который скрывает предыдущий, так как он имеет то же имя.

Отключение значения в F# осуществляется через оператор деструктивного обновления, <-, Это не удастся для неизменных значений, то есть:

> let x = 3;;

val x : int = 3

> x <- 5;;

  x <- 5;;
  ^^^^^^

stdin(2,1): error FS0027: This value is not mutable

Чтобы объявить изменчивую переменную, добавьте mutable после let:

let mutable x = 5;;

val mutable x : int = 5

> x <- 6;;
val it : unit = ()
> x;;
val it : int = 6

Но в чем разница между двумя, спросите вы? Пример может быть достаточно:

let i = 0;
while i < 10 do
    let i = i + 1
    ()

Несмотря на внешность, это бесконечный цикл. i объявлено внутри цикла другое i это скрывает внешнее. Внешний является неизменным, поэтому он всегда сохраняет свою ценность 0 и цикл никогда не заканчивается. Правильный способ написать это с изменяемой переменной:

let mutable i = 0;
while i < 10 do
    i <- i + 1
    ()

x не изменяется, просто скрывается следующей декларацией. Например:

> let x = 4;;
val x : int = 4
> let x = "abc";;
val x : string = "abc"
>

Вы не назначаете 5 для xвы определяете новую переменную.

Следующий пример показывает, что есть две разные переменные. (Это также показывает, что вы можете "получить доступ" к старому x, если он находится в замыкании, используемом другой функцией):

let x = 5;;
let f y = y+x;;
f 10;;
let x = 0;;
f 10;;

доходность

>
val x : int = 5

>
val f : int -> int
> val it : int = 15
>
val x : int = 0

> val it : int = 15

как видите, оба вызова f используют первую переменную x, Определение let x = 0;; определяет новую переменную x, но не переопределяет f,

Вот минимальный пример, иллюстрирующий идентификатор "затенение" (т.е. скрытие) в F#:

let x = 0
do //introduce a new lexical scope
    let x = 1 //"shadow" (i.e. hide) the previous definition of x
    printfn "%i" x //prints 1
//return to outer lexical scope
printfn "%i" x //prints 0, proving that our outer definition of x was not mutated by our inner definition of x

Ваш пример на самом деле немного сложнее, потому что вы работаете в F# Interactive (FSI). FSI динамически испускает код, который выглядит примерно так в вашем примере:

module FSI_0001 =
    let x = 4;;

open FSI_0001 //x = 4 is now available in the top level scope
module FSI_0002 =
    let x = 5;;

open FSI_0002 //x = 5 is now available in the top level scope, hiding x = 4
module FSI_0003 =
    let it = x;;

open FSI_0003
//... subsequent interactions
Другие вопросы по тегам