When to use define and when to use let in racket

寵の児 提交于 2019-12-11 06:47:00

问题


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.


回答1:


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.




回答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.



来源:https://stackoverflow.com/questions/53637079/when-to-use-define-and-when-to-use-let-in-racket

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!