2009-02-08 13 views
19

Jaki jest sens używania operatora przypisania set! w schemacie? Dlaczego nie tylko rebind zmienna na nową wartość przy użyciu define?W Scheme, jaki jest sens "zestawu!"?

> (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 
> 

Odpowiedz

34

Chociaż zarówno define, jak i set! przedefiniują wartość w tym samym zakresie, robią dwie różne rzeczy, gdy zasięg jest inny. Oto przykład:

(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 

Jak widać, gdy tworzymy nowy zakres leksykalny (takich jak, kiedy define funkcją), wszelkie nazwy zdefiniowane w tym zakresie maskować nazwiska, które pojawiają się w zakresie obejmującym. Oznacza to, że po define d x do 4 w foo, naprawdę stworzyliśmy nową wartość dla x, która zacieniała starą wartość. W bar, ponieważ foo nie istnieje w tym zakresie, set! szuka zasięgu obejmującego, aby znaleźć i zmienić wartość x.

Ponadto, jak powiedzieli inni, masz tylko jedną nazwę w zasięgu. Niektóre implementacje pozwolą uciec z wieloma wersjami define s, a niektóre nie. Ponadto, należy używać tylko set! dla zmiennej, która już była define d. Ponownie, jak ściśle ta zasada jest egzekwowana, zależy od implementacji.

3

Podczas korzystania powiązania leksykalne zrobić niedefine im:

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

Podczas korzystania określić utworzyć nową zmienną o nowej wartości, podczas gdy stara zmienna nadal istnieje ze starym wartość; jest po prostu ukryty przez nowy. W linii poleceń nie widać różnicy do ustawienia !, ale definicja nie będzie dostępna dla np. licznik pętli w programie imperatywnym.

+0

Jak zaprojektowałbyś licznik pętli w Scheme? –

5

Zazwyczaj nie jest dozwolona define zmienna więcej niż jeden raz. Większość REPL pozwala na wygodę podczas wypróbowywania rzeczy, ale jeśli spróbujesz to zrobić w programie Scheme, spowoduje to błąd.

Na przykład w mzscheme program

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

daje błąd

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

Ponadto define ma inne znaczenie, gdy używane wewnątrz innych kontekstach. Program

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

ma wyjście

1 
2 
1 

To dlatego define s wewnątrz pewnych konstruktów są właściwie traktowane jako letrec s.