2009-02-08 5 views
19

Quel est le point d'utiliser l'opérateur d'affectation set! dans le schéma? Pourquoi ne pas simplement rebind une variable à une nouvelle valeur en utilisant define?Dans Scheme, quel est le point de "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 
> 

Répondre

34

Bien que tous les deux define et set! redéfinir une valeur lorsque dans la même portée, ils font deux choses différentes lorsque la portée est différente. Voici un exemple:

(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 

Comme vous pouvez le voir, lorsque nous créons un nouveau champ lexical (par exemple lorsque nous define une fonction), les noms définis dans ce champ masquer les noms qui apparaissent dans la portée englobante. Cela signifie que lorsque nous define d x à 4 dans foo, nous avons vraiment créé une nouvelle valeur pour x qui ombragé l'ancienne valeur. Dans bar, puisque foo n'existe pas dans cette portée, set! recherche dans la portée englobante pour rechercher et modifier la valeur de x.

Aussi, comme d'autres personnes l'ont dit, vous êtes seulement supposé define un nom une fois dans une portée. Certaines implémentations vous permettront de sortir avec plusieurs define, et d'autres non. En outre, vous êtes seulement supposé utiliser set! sur une variable qui a déjà été define d. Encore une fois, la stricte application de cette règle dépend de la mise en œuvre.

3

Lorsque vous utilisez des liaisons lexicales vous ne pasdefine les:

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

Lorsque vous utilisez vous définissez créer une nouvelle variable avec la nouvelle valeur, alors que l'ancienne variable existe encore avec l'ancien valeur; c'est juste caché par le nouveau. Sur la ligne de commande, vous ne voyez pas la différence à définir !, mais la définition ne sera pas utilisable par exemple. un compteur de boucle dans un programme impératif.

+0

Comment concevez-vous un compteur de boucles dans Scheme? –

5

Il n'est généralement pas permis de define une variable plus d'une fois. La plupart des REPL le permettent par commodité lorsque vous essayez des choses, mais si vous essayez de le faire dans un programme Scheme, cela vous donnera une erreur.

Par exemple, dans mzscheme, le programme

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

donne l'erreur

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

En outre, define a un sens différent lorsqu'il est utilisé dans d'autres contextes. Le programme

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

a la sortie

1 
2 
1 

C'est parce que define s à l'intérieur de certaines constructions sont effectivement traitées comme letrec s.

Questions connexes