2013-02-18 21 views
5

Quindi so che nello Schema definisce è per scoping dinamico e lasciate per scoping statico, ma la seguente cosa che mi confonde:Scheme Scoping (definire e lasciare)

Se ho

(let ((x 0)) 
    (define f (lambda() x)) 
    (display (f)) 
    (let ((x 1)) 
    (display (f)) 
    ) 
) 

Sarà mostra 00. Fin qui tutto bene. Tuttavia, se aggiungo una definizione aggiuntiva per x in questo modo:

(let ((x 0)) 
    (define f (lambda() x)) 
    (display (f)) 
    (define x 4) 
    (let ((x 1)) 
    (display (f)) 
    ) 
) 

Verrà visualizzato undefined4. Perchè è questo? Perché la definizione di x dopo la valutazione di influisce sul valore restituito di (f)? E perché il valore restituito è "indefinito"?

E 'anche opportuno ricordare che f vincolante con letrec invece di definire funziona anche:

(let ((x 0)) 
    (letrec ((f (lambda() x))) 
    (display (f)) 
    (define x 4) 
    (let ((x 1)) 
    (display (f)) 
    ) 
) 
) 

ritorni 00.

Nota: Ho usato DrRacket con il languge impostato su "abbastanza grande"

+2

Che cosa si intende per "definire è per scoping dinamico nello Schema"? A proposito, a meno che non sia necessario utilizzarlo per un corso, "Pretty Big" è un dialetto obsoleto. – Rhangaun

+3

Scheme usa sempre scope statica, non è corretto affermare che "define is for dynamic e let for scope statico" –

+0

Sono d'accordo con Oscar: la premessa nella domanda è sbagliata, o sta usando il termine sbagliato. – dyoo

risposta

0

Caso 1: il corpo di f si collega al più esterno in entrambe le invocazioni, risultante in 00 come richiede lo scopo statico.

Caso 2: Non sono molto sicuro di ciò, ma l'interno di (define x 4) ombreggia l'x = 0 più esterno, ed è all'interno della portata anche se è testuale dopo la chiamata a f. Quindi un certo ordine di difficoltà di valutazione fa sì che la prima chiamata si verifichi prima che il nuovo x binding sia completamente inizializzato, quindi è "non inizializzato". La seconda chiamata nell'interno let avviene dopo che tutto è stato inizializzato, quindi 4.

Caso 3: Ora che abbiamo esplicitamente messo il letrec e il define in ambiti separati, f ovviamente si riferisce al let esterno. Il definire non fa nulla qui.

5

Il problema riscontrato nel secondo caso è che (define x 42) rende x una variabile per l'intero ambitoin cui è definito. Ora, sebbene la variabile sia definita per l'intero ambito, il suo valore non è definito fino alla riga (define x 42) effettiva.

(let() 
    ;; up here, `x` is defined but has an undefined value 
    ;; ... 
    (define x 42) 
    ;; down here `x` has the value 42 
    ;; ... 
) 

Si sta comportando più come questo:

(let ([x 'undefined]) 
    ;; ... up here, `x` is 'undefined 
    (set! x 42) 
    ;; ... down here, `x` is 42 
) 
+0

Bun dove va 'let ((x 0))' in alto? – Necto

1

I suoi frammenti secondo e terzo codice non sono Scheme (nessuno dei R5RS, R6RS nè R7RS). La <body> (di un let e altri) è definito come:

<body> -> <definition>* <sequence> 
<sequence> -> <command>* <expression> 
<command> -> <expression> 

e quindi una define (che è un <definition>) non può seguiredisplay (a <expression>). È probabile che si ottengano risultati confusi perché il compilatore/interprete gestisce in modo errato l'espansione di "let".

Ecco ciò che un 'buon' compilatore R6RS fa:

> (let ((x 0)) 
    (letrec ((f (lambda() x))) 
    (display (f)) 
    (define x 4) 
    (let ((x 1)) 
    (display (f)) 
    ) 
) 
) 
Unhandled exception 
Condition components: 
    1. &who: define 
    2. &message: "a definition was found where an expression was expected" 
    3. &syntax: 
     form: (define x 4) 
     subform: #f 
    4. &trace: #<syntax (define x 4)> 
> 
+0

Che compilatore usi? – Necto

+0

Ikarus (http://en.wikipedia.org/wiki/Ikarus_(Scheme_implementation)) – GoZoner