Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use define and when to use let in racket

Tags:

scheme

racket

I'm learning racket and I have a question about when to use define and when to use let.

I have this function:

(define my-function
  (lambda (param1 param2 list1)
    (/
     (count
      (lambda (x)

        (define a (param1 (remove x list1)))

        (define b (drop-right x 1))

        (define c (param2 a x-sin-clase))

        (eq? (last x) (last c)))
      (cdr list1))
     (length (cdr list1))))) 

Without knowing what the above function does. Is it correct to use define inside the function body?

I have read somewhere that define is used to declare global variables and let is used to declare local variables. I've look in racket's documentation but it doesn't talk about any difference.

like image 832
VansFannel Avatar asked Dec 05 '18 16:12

VansFannel


People also ask

What is let * In Racket?

Local Binding: let, let*, letrec, ... in The Racket Reference also documents let. A let form binds a set of identifiers, each to the result of some expression, for use in the let body: (let ([id expr] ...) body ...+)

How let and Letrec constructs work in Scheme?

In a let expression, the initial values are computed before any of the variables become bound; in a let* expression, the bindings and evaluations are performed sequentially; while in a letrec expression, all the bindings are in effect while their initial values are being computed, thus allowing mutually recursive ...

How does let work in Scheme?

In Scheme, you can use local variables pretty much the way you do in most languages. When you enter a let expression, the let variables will be bound and initialized with values. When you exit the let expression, those bindings will disappear.

How does let work in Lisp?

The let expression is a special form in Lisp that you will need to use in most function definitions. let is used to attach or bind a symbol to a value in such a way that the Lisp interpreter will not confuse the variable with a variable of the same name that is not part of the function.


1 Answers

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 it's 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 it's 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 it's 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 it's 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.

like image 169
Alex Knauth Avatar answered Nov 15 '22 08:11

Alex Knauth