2013-02-21 13 views
23

Qualcuno può spiegare la differenza semplicemente? Non penso di aver capito il concetto dai libri di testo/siti che ho consultato.Confuso dalla differenza tra let e let * in Schema

+2

possibile duplicato di [Schema Confusing of Let and Let \ *] (http: // stackoverflow.it/questions/8036840/scheme-confusing-of-let-and-let) –

+4

@DavidPfeffer - Non sembra essere un problema. Quello che si chiede è un'interazione molto specifica di 'let' s e 'let *' s, mentre questa richiede una panoramica generale. – Inaimathi

+0

semplicemente confuso spiegazione umana dell'esecuzione della macchina: o – Nishant

risposta

23

Se si utilizza let, non è possibile fare riferimento ai collegamenti precedentemente definiti nella stessa espressione let. Ad esempio, questo non funzionerà:

(let ((x 10) 
     (y (+ x 6))) ; error! unbound identifier in module in: x 
    y) 

Ma se si utilizza let*, è possibile fare riferimento a attacchi precedenti nella stessa let* espressione:

(let* ((x 10) 
     (y (+ x 6))) ; works fine 
    y) 
=> 16 

E 'tutto here nella documentazione.

+1

Non lo vedo chiaramente nella documentazione (dove il tuo link punta, versione corrente 5.3.6), quindi ero anche confuso. La documentazione di 'let' dice che" La prima forma valuta il 'val-exprs' da sinistra a destra, ...", quindi non è chiaro che siano valutati in parallelo. – Alexey

+0

@Alexey non li valuta in parallelo. Come dice la documentazione, * "La prima forma valuta il' val-exprs' da sinistra a destra, crea una nuova posizione per ciascun 'id', e colloca i valori nelle posizioni" * - che significa, prima vengono valutati e i valori risultanti vengono raccolti, e solo *** poi *** vengono create nuove posizioni per ogni * 'id' * e i valori vengono inseriti ciascuno nella sua posizione. È ancora possibile vedere la sequenzialità se uno dei * 'val-exprs' * muta una memoria (cioè dati, come lista o struct) a cui si accede da una successiva. –

26

Let è parallela, (tipo; vedi sotto)let* è sequenziale. Let traduce come

((lambda(a b c) ... body ...) 
    a-value 
    b-value 
    c-value) 

ma let* come

((lambda(a) 
    ((lambda(b) 
     ((lambda(c) ... body ...) 
     c-value)) 
    b-value)) 
    a-value) 

e sta creando così isolati scope nidificati dove b-value espressione può riferirsi a a e c-value espressione può riferirsi sia b e a. a-value appartiene all'ambito esterno. Questo è anche equivalente a

(let ((a a-value)) 
    (let ((b b-value)) 
    (let ((c c-value)) 
     ... body ...))) 

C'è anche letrec, permettendo attacchi ricorsive, in cui tutte le variabili e le espressioni appartenenti ad un ambito condiviso e possono fare riferimento gli uni agli altri (con alcuni avvertimenti relativi alla inizializzazione). È equivalente sia per

(let ((a *undefined*) (b *undefined*) (c *undefined*)) 
    (set! a a-value) 
    (set! b b-value) 
    (set! c c-value) 
    ... body ...) 

(in Racket, disponibile anche come letrec* nello Schema, dal R6RS), o per

(let ((a *undefined*) (b *undefined*) (c *undefined*)) 
    (let ((_x_ a-value) (_y_ b-value) (_z_ c-value)) ; unique identifiers 
    (set! a _x_) 
    (set! b _y_) 
    (set! c _z_) 
    ... body ...)) 

(in Scheme).

aggiornamento: let non valuta effettivamente le sue espressioni di valore in parallelo, è solo che sono tutte valutate nello stesso ambiente iniziale in cui viene visualizzato il modulo let. Questo è anche evidente dal lambda Traduzione sede: primi le espressioni valori vengono valutate ciascuna nello stesso ambiente, esterno, ed i valori risultanti vengono raccolti, e solo allora nuove posizioni vengono creati per ogni id e i valori sono messi ciascuno nella sua posizione. Possiamo ancora vedere la sequenzialità se una delle espressioni di valore muta una memoria (cioè dati, come una lista o una struttura) cui si accede da una successiva.