Recursion Racket是多次运行的过程中的定义表单?

Recursion Racket是多次运行的过程中的定义表单?,recursion,optimization,racket,Recursion,Optimization,Racket,在Racket中,可以在另一个过程中定义一个过程和常数,例如: (define (a a-list) (define something 10) (display a-list) (cond [(empty? a-list) (display "done")] [else (display a-list) (newline) (a (rest a-list))])) 打印列表,然后删除第一个元素,然后再次打印列表,依此类推,直到列表为空 在示

在Racket中,可以在另一个过程中定义一个过程和常数,例如:

(define (a a-list)
  (define something 10)
  (display a-list)
  (cond
    [(empty? a-list) (display "done")]
    [else
      (display a-list) (newline)
      (a (rest a-list))]))
打印列表,然后删除第一个元素,然后再次打印列表,依此类推,直到列表为空

在示例过程中,无论出于何种原因,值
something
被定义为
10
。当程序递归时,Racket是否再次定义了该值,或者是否足够明智地注意到该定义没有改变

此外,如果未对其进行优化,并且根据
something
的定义,每个递归步骤将消耗更多内存,则它可能位于前面调用的过程的堆栈空间中。例如,让我们假设列表中有一百万个数字,但从不改变数字。显然,如果该定义中的内容依赖于作为参数给出的列表,则不能简单地对其进行优化


如果这没有得到优化,那么在递归函数中不要有太多的
define
表单,还是只使用占用很少空间的表单?但是,将它们放在过程之外会使它们可以从其他过程访问,即使只有一个过程使用过它们。

每次调用过程时都会计算
定义表达式。考虑这个例子:

(define (test1)
  (define x (begin (display "Hello from test1 ") 10))
  x)

(test1)
=> Hello from test1 10
(test1)
=> Hello from test1 10
(test1)
=> Hello from test1 10
如果希望过程中的值只计算一次(当创建过程本身时),则可以将其放在过程之外的范围内,因为
lambda
在其词法环境中定义了:

(define test2
  (let ((x (begin (display "Hello from test2") 20)))
    (lambda () x)))

=> Hello from test2
(test2)
=> 20
(test2)
=> 20
(test2)
=> 20

我不明白第一个例子。当然,当我调用该过程时,它将打印
x
的值。我很想知道,是否有优化在幕后进行,以避免每次都必须定义
x
的值,因为每次都是一样的。但是,关于如何使用闭包的建议似乎很好,以防在过程中(或者在一般情况下?)没有针对不变定义的优化。也许我应该问“球拍的JIT是否优化了过程中不变值的定义?”你不明白-是的,它会打印
x
,但每次都会打印
显示部分的值。每次都必须对定义进行评估,这是不可优化的。啊,现在我明白了!谢谢我不明白的是,为什么不管它是什么样的定义,它都是完全不可优化的。我的意思是像
(定义一个10)
和其他不变的值定义。因此,我想最好使用第二个示例中使用的方法,避免多次计算相同的不变内容?绑定到
define
中的值的表达式可以在每次执行过程时更改,或者变量本身可以在过程中修改或重新分配,因此编译器别无选择,只能每次对它求值。所以,是的,如果你需要一个表达式只计算一次,就像我们在第二个例子中所做的那样。你知道一个网站或其他来源,它列出了类似于Racket中的最佳实践,包括你的第二个例子,以及你给出的解释吗?我想从一开始就“用正确的方法”学习球拍。