为什么内部程序?

时间:2015-03-03 13:28:02

标签: scheme procedure

(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-1decode使用相同的参数,为什么我们甚至需要decode-1

2 个答案:

答案 0 :(得分:1)

decode-1实际上是指decode参数tree(在(decode-1 (cdr bits) tree)中),而不仅仅是current-branch。所以他们不是“相同的论点”。 (在技术方面,decode-1closure。)

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

顺便说一句,“定义一个过程并调用它”这个习惯用法非常普遍,Scheme提供了一个"named let" syntax来更好地编写它:

(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 :(得分:0)

制作此类内部过程的一个优点是您可以简单地修改其实现而无需更改参数计数。例如,添加一个额外的参数作为过程的累加器,以便它可以是尾递归的。 decode-1 正确的尾递归,因此如果 tree 太大,则实现可能会导致堆栈溢出。

以下是转换decode尾递归调用的示例:

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

<强>已更新

上面的代码也可以用named-let编写。因此,当您想用内部定义编写它时,情况将是以下情况。

  1. 如果内部程序有交叉引用,那么它可以是您可以选择的选项之一。这也可以通过letrec完成,但嵌套级别会稍微深一些。因此,在您的情况下,choose-branch可以在decode过程中编写。
  2. 如果顶层过程包含define-syntax的内部宏定义,那么您只能使用内部定义编写它。 R7RS的let(rec)-syntax创建了一个范围,但内部define-syntaxdefine应该被视为在同一范围内。
  3. 我不确定R7RS是否指定了内部宏的扩展方式(例如,首先扩展所有宏,如R6RS)。