Одно отличие: внутренние определения находятся во взаимно рекурсивной области, но пусть привязки - нет.
Это означает, что в let
:
(let ([x expr-1] [y expr-2])
body)
expr-1
иexpr-2
не может относиться к x
или y
.Более конкретно,
(let ([x (stream-cons 1 y)] [y (stream-cons 2 x)])
x)
;error=> y: unbound identifier in: y
И если x
или y
определен вне let
, expr-1 и expr-2 будут ссылаться на external определения,а не те, которые введены в let.Конкретно:
(define x 'outer)
(let ([x 'inner] [y x]) ; <- this x refers to outer,
y) ; so y is 'outer
;=> 'outer
Однако внутренние определения имеют взаимно рекурсивную область, что означает, что в
(block
(define x expr-1)
(define y expr-2)
body)
expr-1
и expr-2
могут ссылатьсядо x
или y
.Конкретно,
(require racket/block)
(block
(define x (stream-cons 1 y))
(define y (stream-cons 2 x))
(stream->list (stream-take x 5)))
;=> (list 1 2 1 2 1)
Сфера define
....A....
(define (f)
(define t1 ..B..)
(define x ..C..)
(define t2 ..D..)
....E....)
....F....
x
видна повсюду в теле f
, но не снаружи этого.Это означает, что он виден в B
, C
, D
и E
, но не в A или F.
Область действия let
....A....
(define (f)
(let ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
Здесь x
виден повсюду в теле let
, но не снаружи.Это означает, что он виден в E
, но не в A, B, C, D или F.
Область действия let*
....A....
(define (f)
(let* ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
Здесь x
виден повсюду в теле let*
и в let*
привязках, которые приходят после этого, но не снаружи этого.Это означает, что он виден в D
и E
, но не в A, B, C или F.
Область действия letrec
....A....
(define (f)
(letrec ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
x
виден повсюду в теле letrec
и в привязках letrec
, но не снаружи.Это означает, что он виден в B
, C
, D
и E
, но не в A или F.
Область переменных в letrec
и область локальных define
переменные очень похожи, потому что и letrec
, и define
работают с взаимно рекурсивными областями.