# scheme – When to use define and when to use let in racket

## scheme – When to use define and when to use let in racket

One difference: Internal defines are in a mutually recursive scope, but let bindings are not.

This means than in a `let`:

``````(let ([x expr-1] [y expr-2])
body)
``````

The `expr-1` and `expr-2` cannot refer to `x` or `y`. More concretely,

``````(let ([x (stream-cons 1 y)] [y (stream-cons 2 x)])
x)
;error=> y: unbound identifier in: y
``````

And if `x` or `y` is defined outside of the `let`, expr-1 and expr-2 will refer to the outer definitions, and not the ones introduced by the let. Concretely:

``````(define x outer)
(let ([x inner] [y x]) ; <- this x refers to outer,
y)                    ;    so y is outer
;=> outer
``````

However, internal defines have a mutually recursive scope, which means that in

``````(block
(define x expr-1)
(define y expr-2)
body)
``````

The `expr-1` and `expr-2` can refer to `x` or `y`. Concretely,

``````(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)
``````

### The Scope of a `define`

``````....A....
(define (f)
(define t1 ..B..)
(define x ..C..)
(define t2 ..D..)
....E....)
....F....
``````

The `x` is visible everywhere in the body of `f`, but not outside that. That means its visible in `B`, `C`, `D`, and `E`, but not in A or F.

### The Scope of a `let`

``````....A....
(define (f)
(let ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
``````

Here the `x` is visible everywhere in the body of the `let`, but not outside that. That means its visible in `E`, but not in A, B, C, D, or F.

### The Scope of a `let*`

``````....A....
(define (f)
(let* ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
``````

Here the `x` is visible everywhere in the body of the `let*` and in `let*` bindings that come after it, but not outside that. That means its visible in `D` and `E`, but not in A, B, C, or F.

### The Scope of a `letrec`

``````....A....
(define (f)
(letrec ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
``````

The `x` is visible everywhere in the body of the `letrec` and in the bindings of the `letrec`, but not outside that. That means its visible in `B`, `C`, `D`, and `E`, but not in A or F.

The scope of variables in `letrec` and the scope of local `define` variables are very similar because both `letrec` and `define` work with mutually recursive scopes.

Ive finally understood what I have read that `define`s variable are global variables.

In the book The Scheme Programming Language Fourth Edition, R. Kent Dybvig, section 2.6. Top Level Definitions says:

The variables bound by let and lambda expressions are not visible
outside the bodies of these expressions.