Scheme 为什么是内部程序?

Scheme 为什么是内部程序?,scheme,procedure,Scheme,Procedure,如果我们对decode和decode-1使用相同的参数,为什么我们甚至需要decode-1?decode-1实际上指的是decode参数树(在(解码-1(cdr位)树中)),而不仅仅是指当前分支。所以他们不是“相同的论点”。(在技术术语中,decode-1是一种编码。) 如果decode-1没有引用树(或者通常没有引用任何外部变量),那么是的,您可以直接递归到decode,而不需要内部过程 顺便说一句,“定义一个过程并调用它”的习惯用法非常常见,Scheme提供了一个更好地编写它的方法: (de

如果我们对
decode
decode-1
使用相同的参数,为什么我们甚至需要
decode-1

decode-1
实际上指的是
decode
参数树(在
(解码-1(cdr位)树中)
),而不仅仅是指
当前分支
。所以他们不是“相同的论点”。(在技术术语中,
decode-1
是一种编码。)

如果
decode-1
没有引用
树(或者通常没有引用任何外部变量),那么是的,您可以直接递归到
decode
,而不需要内部过程

顺便说一句,“定义一个过程并调用它”的习惯用法非常常见,Scheme提供了一个更好地编写它的方法:

(define (decode bits tree)
  (define (decode-1 bits current-branch)
    (if (null? bits)
        '()
        (let ((next-branch (choose-branch (car bits) current-branch)))
          (if (leaf? next-branch)
              (cons (symbol-leaf next-branch)
                    (decode-1 (cdr bits) tree))
              (decode-1 (cdr bits) next-branch)))))
  (decode-1 bits tree))

创建这样一个内部过程的优点是,您可以简单地修改它的实现,而无需更改参数计数。例如,添加一个额外的参数作为过程的累加器,以便它可以是尾部递归的
decode-1
不是正确的尾部递归,所以如果位和树太大,那么实现可能会导致堆栈溢出

下面是一个转换
decode
尾部递归调用的示例:

(define (decode bits tree)
  (let decode-1 ((bits bits) (current-branch tree))
    (if (null? bits)
        '()
        (let ((next-branch (choose-branch (car bits) current-branch)))
          (if (leaf? next-branch)
              (cons (symbol-leaf next-branch) (decode-1 (cdr bits) tree))
              (decode-1 (cdr bits) next-branch))))))
(定义(解码位树) (定义(解码-1位当前分支acc) (如果为空位) (倒车加速) (let((下一个分支(选择分支(汽车位)当前分支))) (如果(叶?下一分支) (解码-1(cdr位)树(cons(符号叶下一分支)acc)) (解码-1(cdr位)下一分支acc(()()))) (解码-1位树“())) 已更新

上面的代码也可以使用命名let编写。因此,当您想用内部定义编写它时,情况如下

  • 如果内部程序有交叉引用,那么它可以是您可以选择的选项之一。这也可以通过
    letrec
    实现,但嵌套级别会稍微深一些。因此,在您的情况下,
    choose branch
    可以写入
    decode
    过程中
  • 如果toplevel过程包含带有
    定义语法的内部宏定义
    ,则只能使用内部定义编写。R7RS的
    let(rec)-语法
    创建了一个作用域,但内部
    定义语法
    定义
    应被视为处于同一作用域中
    我不确定R7RS是否指定内部宏的扩展方式(例如,首先扩展所有宏,如R6RS)。

    否,您不能“简单地消除内部定义”。正如我在回答中提到的,内部过程是一个闭包。事实上,即使您的尾部递归定义仍然是一个闭包,因此您仍然无法在不添加额外的
    参数的情况下将其提升到顶级过程。对不起,我没有注意到
    参数。前两句应该是。你能解释一下尾部递归版本是如何工作的吗?我看不懂代码。。。如果位为空,为什么要反转acc?我现在明白为什么要反转acc。。。是否可以这样做,这样您就不必将其反转?您也可以使用
    append
    而不是
    cons
    来避免
    反转
    ,但这需要O(n^2)的成本,因为追加了O(n)。 (define (decode bits tree) (define (decode-1 bits current-branch acc) (if (null? bits) (reverse acc) (let ((next-branch (choose-branch (car bits) current-branch))) (if (leaf? next-branch) (decode-1 (cdr bits) tree (cons (symbol-leaf next-branch) acc)) (decode-1 (cdr bits) next-branch acc))))) (decode-1 bits tree '()))