Qualcuno può spiegare la differenza semplicemente? Non penso di aver capito il concetto dai libri di testo / siti che ho consultato.
Se si utilizza let
, non è ansible 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 usi let*
, è ansible fare riferimento ai binding precedenti nella stessa espressione let*
:
(let* ((x 10) (y (+ x 6))) ; works fine y) => 16
È tutto qui nella documentazione.
Let
è parallelo, (tipo di; vedi sotto) let*
è sequenziale. Let
tradurre come
((lambda(abc) ... body ...) a-value b-value c-value)
ma let*
come
((lambda(a) ((lambda(b) ((lambda(c) ... body ...) c-value)) b-value)) a-value)
e quindi sta creando blocchi di scope annidati in cui l’espressione di b-value
può riferirsi a a
, e l’espressione di c-value
può riferirsi sia a b
che a
. a-value
-app appartiene allo scope esterno. Questo è anche equivalente a
(let ((a a-value)) (let ((b b-value)) (let ((c c-value)) ... body ... )))
Esiste anche letrec
, che consente binding ricorsivi, in cui tutte le variabili e le espressioni appartengono a uno scope condiviso e possono riferirsi l’un l’altro (con alcune avvertenze relative all’inizializzazione). È equivalente a
(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*
in Scheme, da R6RS ), o in
(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 Schema ).
aggiornamento: let
realtà non valuta le sue espressioni di valore in parallelo, è solo che sono tutte valutate nello stesso ambiente iniziale in cui appare il modulo let
. Ciò è chiaro anche dalla traduzione basata su lambda
: prima le espressioni di valore vengono valutate ciascuna nello stesso ambiente esterno , e i valori risultanti vengono raccolti, e solo allora vengono create nuove posizioni per ogni id e i valori vengono inseriti 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.