2009-02-08 32 views
19

在方案中使用set!賦值運算符有什麼意義?爲什麼不使用definerebind變量設置爲新值?在Scheme中,「set!」是什麼意思?

> (define x 100) 
> (define (value-of-x) x) ;; value-of-x closes over "x" 
> x 
100 
> (value-of-x) 
100 
> (set! x (+ x 1)) 
> x 
101 
> (value-of-x) 
101 
> (define x (+ x 1)) 
> x 
102 
> (value-of-x) 
102 
> 

回答

34

儘管defineset!將在同一範圍內重新定義值,但當範圍不同時它們會做兩件不同的事情。這裏有一個例子:

(define x 3) 

(define (foo) 
    (define x 4) 
    x) 

(define (bar) 
    (set! x 4) 
    x) 

(foo) ; returns 4 
x  ; still 3 
(bar) ; returns 4 
x  ; is now 4 

正如你所看到的,當我們創建了一個新的詞彙範圍(比如當我們define一個函數),在該範圍內定義的任何名稱掩蓋了出現在封閉範圍的名稱。這意味着當我們define d x4foo中,我們確實創造了一個新值x,它隱藏了舊值。在bar中,由於foo在該範圍內不存在,因此set!查找封閉範圍以查找並更改x的值。

另外,正如其他人所說,你只應該在名稱範圍內登錄一次名稱define。有些實現會讓你脫離多個define,有些不會。此外,你只應該使用set!上的變量已經是define d。再次強調,這個規則的執行程度取決於實施。

3

當您使用詞法綁定你define他們:

(let ((x 1)) 
    (set! x (+ x 1)) 
    x) 
2

當您使用定義您創建具有新值的新變量,而舊的變量仍與舊存在值;它只是被新的隱藏。在命令行中,您看不到要設置的區別!但定義將不可用於強制性計劃中的循環計數器。

+0

你會如何在Scheme中設計一個循環計數器? – 2015-02-22 16:51:15

5

它通常不會被允許多次給變量define。大多數REPLs在您試用時允許它方便,但如果您在Scheme程序中嘗試這樣做,它會給您一個錯誤。

例如,在MzScheme的,程序

#lang scheme 
(define x 1) 
(define x 2) 

給出了錯誤

test.ss:3:8: module: duplicate definition for identifier at: x in: (define-values (x) 2) 

此外,define具有不同的含義其它上下文的內使用時。程序

#lang scheme 
(define x 1) 
x 
(let() 
    (define x 2) 
    x) 
x 

具有輸出

1 
2 
1 

這是因爲define條某些構建體內部實際上爲letrec小號處理。