【问题标题】:When to use define and when to use let in racket什么时候使用define,什么时候使用let in racket
【发布时间】:2018-12-05 16:50:34
【问题描述】:

我正在学习球拍,我有一个关于何时使用define 以及何时使用let 的问题。

我有这个功能:

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

不知道上面的函数是做什么的。在函数体内使用define是否正确?

我在某处读到define 用于声明全局变量,let 用于声明局部变量。我查看了球拍的文档,但没有说任何区别。

【问题讨论】:

  • 一个区别:内部defines在相互递归作用域(包括mut-rec函数),let绑定不是,但也有其他风格原因
  • @AlexKnauth 抱歉,我对您的评论一无所知。谢谢。
  • (let ([x expr-1] [y expr-2]) body) 中,expr-1 和 expr-2 不能引用xy。 . . . . . .但是,在 (block (define x expr-1) (define y expr-2) body) 中,expr-1 和 expr-2 都可以引用 xy
  • 技术上defines 仅在顶层“允许”。在本地定义上下文中使用时,它们只是语法糖,将扩展为适当的let 形式。

标签: scheme racket


【解决方案1】:

一个区别:内部定义在相互递归的范围内,但 let 绑定不在。

这意味着比let

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

expr-1expr-2 不能引用 xy。更具体地说,

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

如果xylet 之外定义,则expr-1 和expr-2 将引用外部 定义,而不是由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-1expr-2 可以xy。具体来说,

(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....

xf 的正文中随处可见,但在此之外不可见。这意味着它在 BCDE 中可见,但在 A 或 F 中不可见。

let 的作用域

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

这里xlet 的主体中随处可见,但在其之外不可见。这意味着它在 E 中可见,但在 A、B、C、D 或 F 中不可见。

let* 的作用域

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

这里xlet* 的主体中和在它之后let* 绑定中随处可见,但不在此之外。这意味着它在 DE 中可见,但在 A、B、C 或 F 中不可见。

letrec 的作用域

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

xletrec 的主体和letrec 的绑定中随处可见,但在此之外不可见。这意味着它在 BCDE 中可见,但在 A 或 F 中不可见。

letrec 中变量的作用域和本地变量define 的作用域非常相似,因为letrecdefine 都使用相互递归的作用域。

【讨论】:

  • 那么,在 body 函数中使用 let 更好吗?谢谢。
  • 我发现let 在我需要将函数输入“更改”为更好的“更一致”形式时最有用。例如,如果一个函数采用Symbol[Listof Symbol],但我想编写函数的主体,就好像它始终是[Listof Symbol],我可以使用let 来隐藏参数并使它是一个列表。 (define (f x) (let ([x (if (list? x) x (list x))]) ....body....))
  • 我对所有这些不同的范围界定有点不知所措。有没有关于它们使用百分比的统计数据?到目前为止,主要使用的是定义和一些让,这似乎已经足够了。我们需要这么多选择吗?
  • 我不知道任何具体的统计数据,但是在我阅读或工作过的代码中,内部定义比让更常见。我通常只在特殊情况下才使用 let
  • 用“标准化”版本遮蔽?
【解决方案2】:

我终于明白我读到的define的变量是“全局变量”。

在《方案编程语言第四版》一书中,R. Kent Dybvig,2.6. Top Level Definitions 部分说:

let 和 lambda 表达式绑定的变量不可见 在这些表达式的主体之外。

【讨论】:

  • 如果定义在本地范围内,define 的变量是全局的。 (define (f) (define x 5) ....body....) 中的 x 仅在 f 的内部可见,在外部不可见。
  • @AlexKnauth 也许我还没有理解我的教授。他说:“define 应该只用于定义全局变量。要从函数中定义局部变量,必须使用 let 或 let *。否则,全局变量可能会干扰函数的局部运行。”
  • 您的教授确切地说说的是哪种语言?这听起来像是一个奇怪的语言功能,我想尝试一下。
  • 我只是尝试在 Racket 中以这种方式使用内部定义,而 x 在外部不可见,它不是“全局的”。那么你的教授是什么意思呢?
  • @AlexKnauth 他说是关于闭包的,en.wikipedia.org/wiki/Closure_(computer_programming)
猜你喜欢
  • 2012-03-19
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 2014-06-04
  • 2017-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多