When to use define and when to use let in racket
Asked Answered
R

2

6

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.

Rhombencephalon answered 5/12, 2018 at 16:50 Comment(4)
One difference: Internal defines are in a mutually recursive scope (including mut-rec functions), let bindings are not, but there are also other style reasonsChiller
@AlexKnauth Sorry, but I haven't understood anything about your comment. Thanks.Rhombencephalon
In (let ([x expr-1] [y expr-2]) body), expr-1 and expr-2 cannot refer to x or y. . . . . . . However, in (block (define x expr-1) (define y expr-2) body), both expr-1 and expr-2 can have references to x and y.Chiller
Technically defines are only "allowed" on the top level. When used in local definition context, them are just syntax sugar and will be expanded into appropriate let form.Amaryllis
C
15

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.

Chiller answered 5/12, 2018 at 21:21 Comment(6)
So, is it better to use let inside a body function? Thanks.Rhombencephalon
I find let most useful when I need to "change" the function input to be a better "more consistent" form of itself. For example if a function takes either a Symbol or a [Listof Symbol], but I want to write the body of the function as if it were consistently a [Listof Symbol], I could use a let to shadow the argument and make it a list. (define (f x) (let ([x (if (list? x) x (list x))]) ....body....))Chiller
I'm a bit overwhelmed by all these various scoping's. Are there any statistics on the % amount of their use? So far been using mainly define's and a bit of lets and it seemed enough. Do we need so many options?Fawnfawna
I don't know any specific statistics, but in the code I've read or worked on, internal define is much more common than let. I normally only use let in special circumstances like when either define isn't allowed or I'm intentionally shadowing with a "normalized" version, for everything else I use defineChiller
shadowing with a "normalized" version?Fawnfawna
The comment above with changing x to a better "more consistent" form of itself, making it always a list, instead of sometimes a list and sometimes a symbol, is one example of a way to "normalize" x.Chiller
R
-2

I've 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.

Rhombencephalon answered 5/12, 2018 at 16:50 Comment(9)
define's variables are not global if the definition is within a local scope. The x in (define (f) (define x 5) ....body....) is only visible inside the body of f, not outside.Chiller
@AlexKnauth Maybe I haven't understood my professor. He said: "Define should be used only to define global variables. To define local variables from a function, let or let * must be used. If not, global variables may interfere with the local functioning of a function."Rhombencephalon
Which language exactly is your professor talking about? That sounds like a weird language feature and I want to try it out.Chiller
He's talking about Scheme.Rhombencephalon
Which variant of Scheme? R5RS, R6RS, Chez Scheme, Guile, Chicken, etc. which one?Chiller
We are developing our exercises with racket. We use DrRacket.Rhombencephalon
I just tried using an internal define that way in Racket, and the x wasn't visible outside, it wasn't "global." So what did your professor mean by that?Chiller
I don't know. I will ask him. Maybe tomorrow I will get an answer. Thanks for your time.Rhombencephalon
@AlexKnauth He said that is about Closure, en.wikipedia.org/wiki/Closure_(computer_programming)Rhombencephalon

© 2022 - 2024 — McMap. All rights reserved.