2009-02-08 9 views
19

Worauf kommt es an, den Zuweisungsoperator set! im Schema zu verwenden? Warum nicht einfach rebind eine Variable auf einen neuen Wert mit define?In Schema, was ist der Sinn von "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 
> 

Antwort

34

Obwohl sowohl als auch set! einen Wert im selben Bereich neu definieren, führen sie zwei verschiedene Dinge aus, wenn der Bereich anders ist. Hier ein Beispiel:

(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 

Wie Sie sehen können, wenn wir einen neuen lexikalischen Gültigkeitsbereich (wie wenn wir define eine Funktion) erstellen, werden alle definierten Namen innerhalb dieses Bereichs den Namen Maske, die in dem umschließenden Umfang erscheinen. Dies bedeutet, dass wir, als wir d x bis 4 in foo haben, wirklich einen neuen Wert für x erstellt haben, der den alten Wert überschattet hat. In bar, da foo nicht in diesem Bereich existiert, sucht set! zum umschließenden Bereich, um den Wert x zu finden und zu ändern.

Auch, wie andere Leute gesagt haben, sollen Sie nur einen Namen einmal in einem Bereich. Einige Implementierungen werden Sie mit mehreren s entkommen lassen, und einige nicht. Außerdem sollten Sie nur set! für eine Variable verwenden, die bereits d ist. Wie streng diese Regel durchgesetzt wird, hängt wiederum von der Implementierung ab.

3

Wenn Sie lexikalische Bindungen verwenden tun Sie nichtdefine sie:

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

Wenn Sie definieren verwenden Sie eine neue Variable mit dem neuen Wert zu schaffen, während die alte Variable existiert noch mit dem alten Wert; es ist nur von dem Neuen versteckt. In der Befehlszeile sehen Sie nicht den Unterschied zu setzen!, Aber definieren wird nicht verwendbar für z. ein Schleifenzähler in einem imperativen Programm.

+0

Wie würden Sie einen Loop-Zähler in Scheme entwerfen? –

5

Es ist in der Regel nicht zulässig, eine Variable mehr als einmal. Die meisten REPLs erlauben es, wenn Sie Dinge ausprobieren, aber wenn Sie das in einem Scheme-Programm versuchen, erhalten Sie einen Fehler.

Zum Beispiel in mzscheme, das Programm

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

gibt dem Fehler

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

Zusätzlich define eine andere Bedeutung hat, wenn innerhalb von anderen Kontexten verwendet. Das Programm

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

weist das Ausgangs

1 
2 
1 

Dies liegt daran, define s innerhalb bestimmter Konstrukte werden als letrec s tatsächlich behandelt.