2014-09-23 8 views
5

Una buona domanda è stato chiesto sul canale #scheme di Freenode. Si consideri il seguente codice in Scheme:macro e definizioni interne a schema

(define alpha 1) 

(define-syntax foo 
    (syntax-rules (quote alpha) 
    ((_ alpha msg) (define bar 2)) 
    ((_ other msg) (syntax-error msg)))) 

(define (beta) 
    (foo alpha "beta") 
    (define alpha 3) 
    'beta) 

(define (gamma) 
    (define alpha 4) 
    (foo alpha "gamma") 
    'gamma) 

(define (delta alpha) 
    (foo alpha "delta") 
    'delta) 

Quali quelli di beta, gamma, e delta dovrebbe produrre errori di sintassi? E quale do? Ho verificato questo con Chibi schema in cui beta va bene mentre gamma e delta falliscono. Mi chiedo se si tratti di un comportamento intenzionale o di un bug in Chibi.

Secondo lo standard, sembra che l'espansione delle macro dovrebbe avvenire prima che le definizioni interne vengano riscritte in letrec*. Così beta e gamma dovrebbe fallire come sia foo abbinerà con una internamente definita alpha, non quello globale.

Tuttavia, non è esplicitamente specificato nella norma come definizioni interne in realtà il lavoro, solo che possono essere pensato come una scorciatoia letrec. Ho lo stesso comportamento con R5RS di Racket, quindi sembra che mi manchi qualcosa nello standard che richiede tale comportamento.

+0

In R6RS (impl base psyntax), ottengo lo stesso comportamento quando si chiama le procedure. – leppie

risposta

1

OK, I finalmente capire la tua domanda. Eseguire il tuo codice è stato impegnativo, perché sembra che tu abbia una funzione di 'sintassi-errore' che segnala un errore di sintassi solo se si verifica in un codice completamente espanso. Qualunque cosa.

Penso che la risposta alla tua domanda è questa:

Questi ragazzi Scheme (Dybvig, Felleisen, Hieb, Clinger, Rees, Wand, Flatt, Culpepper, ecc) sono piuttosto intelligente!

In particolare, in qualche modo Scheme/Racket riesce a capire come la struttura di legame funziona anche quando non sa cosa sta per essere un vincolante o no. Hai ragione! Questo è pazzesco! Ma l'algoritmo delineato da Dybvig et al. fa cose molto intelligenti per garantire che l'igiene rintracci se gli identificatori sono "identificatore libero-uguale" o "identificatore-identico-legato" (terminologia di Flatt) anche quando non sa ancora quale lega l'altro. Personalmente raccomando di leggere "Macro che funzionano insieme" (Flatt, Culpepper, Darais, Findler) per una migliore comprensione di questo.

Mi scuso se ho frainteso la tua domanda, o se il mio tono è inadeguato!

1

potrebbe essere un po 'troppo dipende lato attuazione ma questo comportamento è dovuto dell'ordine di macro espansione. In teoria, tutte le definizioni contengono alpha quindi non dovrebbe corrispondere a quello in parole chiave letterali. Tuttavia, è necessario eseguire l'espansione macro prima che i moduli define vengano espansi su letrec*, altrimenti il ​​compilatore non è in grado di rilevare correttamente la definizione interna. Quindi in quel momento, il compilatore può o non può vedere i binding. (La tempistica espansione macro è non specificato R7RS, così attuazione può scegliere proprio temporizzazione pure.)

Per il caso beta, compilatore non prendere il legame modo macro espansore comunque possibile che alpha è lo stesso vincolante come globale. Gli altri casi sono in un altro modo.

0

Prima di tutto, delta è fuori (non dovrebbe corrispondere alpha) perché si lega chiaramente lessicalmente alpha ad un'altra vincolante rispetto a quello in base al quale i tuoi sytnax-rules appare. I più interessanti sono beta e gamma.

Come da sezione 5.2.2. di R4RS (pagina 13) e R5RS (pagina 16), sezione 5.3.2. di R7RS (pagina 26) e sezione 11.3. di R6RS (p 32), la "regione" di un'associazione stabilita tramite una definizione interna è l'intero <body> in cui la definizione appare. E la tua macro chiamata a foo è chiaramente all'interno dello stesso <body> come quelle definizioni interne.

R7RS va anche un po 'oltre e ci avverte:

Si noti che un tale organismo [vale a dire quello che contiene le definizioni interne] potrebbe non essere evidente fino a dopo l'espansione di altre sintassi.

Quindi l'ordine incasinato degli eventi è ammesso, ma non c'è ambiguità; il tuo syntax-rules non deve corrispondere al ramo alpha se esiste un collegamento per alpha da una definizione interna nello stesso <body> come chiamata alla macro. Pertanto, anche beta e gamma sono fuori.

Appendice A

Se abbiamo complicato la situazione ulteriormente, e la vostra stessa macro condizionale legati alpha, come

(syntax-rules (alpha) 
    ((_ alpha x) (define alpha x))) 

allora sembra veramente ambiguo al primo pensiero, ma credo che questo sia risolto attraverso il fatto che l'espansione macro rinominerà l'identificatore alpha definito per l'igiene, il che significa che non staremmo ombreggiamo il alpha che stiamo corrispondendo come un valore letterale, quindi la corrispondenza va bene, e e sopra semplicemente creerà un binding per un rinominato alpha che non è raggiungibile al di fuori del corpo della macro.

Appendice B

C'è un vincolo alla fine del paragrafo 5.3. di R5RS (pagina 17), alla fine della sezione 5.4. di R7RS (pagina 26) e la parte centrale della sezione 10. in R6RS (pagina 30), che menziona che una sequenza di definizioni non deve contenere una definizione che modifichi il significato di ognuna di esse. (In realtà è un po 'più complicato, tutti e tre gli standard utilizzando formulazione diversa, ma che dovrebbe essere una sintesi ragionevole.)

Nel tuo esempio, non è chiaro se la possibilità del vostro syntax-rules espansione per una sintassi conteggio degli errori come un'ambiguità del suo "significato". Se lo si considera un'ambiguità, allora i tuoi beta e gamma sono "errori" (comportamento non definito) come da R5RS e R7RS e una "violazione della sintassi" come da R6RS.

Se il vostro esempio conteneva un'altra vincolante nel secondo ramo del syntax-rules (idealmente una definizione per la stessa variabile, anche), allora questo nitpick non si applica, quindi la tua domanda sorge.