2012-06-22 3 views
8

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

> let x = 4;; 

val x : int = 4 

> let x = 5;; 

val x : int = 5 

> x;; 
val it : int = 5 
> 

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

+1

Возможный дубликат http://stackoverflow.com/questions/2844047/what-is-the-let-keyword-in-functional-languages -like-f-and-ocaml-for.Ответы там объясняют различие между привязкой переменной и присваиванием переменной. – Heatsink

+1

@Alex: вы можете найти ответы на [этот вопрос] (http://stackoverflow.com/questions/2478079/f-shadowing-and-nested-function). – Daniel

+0

Вопрос аналогичный, но это не дубликат. –

ответ

14

При записи 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 
    () 
5

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

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

В чем разница между скрытыми и неизменяемыми? Означает ли это, что я все еще могу получить предыдущее значение x? – Alexan

+1

@Alex см. Мой ответ для объяснения разницы. – Asik

4

Вы не назначая 5 до 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 

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

3

Вот минимальный пример, иллюстрирующий идентификатор «теневое» (т.е. скрытие) в 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 
Смежные вопросы