Recursion scheme中的递归:基本情况和意外错误

Recursion scheme中的递归:基本情况和意外错误,recursion,scheme,Recursion,Scheme,我是一个scheme noob,自学scheme,以此加深对功能风格和技术的理解。我遇到了递归和基本情况的问题 当递归遇到基本情况时,有时会出现意外错误: ERROR: In procedure #<unspecified>: ERROR: Wrong type to apply: #<unspecified> 这些都是帮助我理解递归机制的玩具程序。我想了解为什么程序贴上标签;;糟糕的错误 ;;good (define (pt t) (if (> t 0)

我是一个scheme noob,自学scheme,以此加深对功能风格和技术的理解。我遇到了递归和基本情况的问题

当递归遇到基本情况时,有时会出现意外错误:

ERROR: In procedure #<unspecified>:
ERROR: Wrong type to apply: #<unspecified>
这些都是帮助我理解递归机制的玩具程序。我想了解为什么程序贴上标签;;糟糕的错误

;;good
(define (pt t)
   (if (> t 0)
       ((display t)
    (pt (- t 1)))))
我怀疑问题与if不是一个程序有关。如果有人能给我指出正确的方向,我将不胜感激

我使用的方案是guile 2.0.11,一个接一个:

(define (pt t)
   (display t)
   (if (> t 0)
       (pt (- t 1))))
表示,显示接收到的参数值,然后,如果大于0,则将其减少1并重复;否则什么也不做。所以它很好,甚至是尾部递归;给定一个数字,它将在没有任何间距的情况下打印所有递减的数字,直到它达到0

但是由于if表单中没有可选子句,因此最终没有返回值。在这种情况下,标准未指定返回值。让它被退回是不整洁的;在这里,我们看到它在所有的数字都打印出来后返回。但这本身并不是一个错误,只有尝试使用这样的值才是一个错误

;;good
(define (pt t)
   (if (> t 0)
       ((display t)
    (pt (- t 1)))))
这里的缩进是误导性的;display t pt-t1表示显示t,然后调用其未定义的结果,就好像它是一个函数,而它不是。令人不快的e、 麻省理工学院的计划说:;对象[未指定的返回值]不适用。-先打印1后

为什么??因为要找出display t的返回值,必须首先执行它。但为什么在测试pt 5时为1而不是5?因为要计算fx,Scheme必须首先找出f和x的值,并且它是按未指定的顺序进行计算的

MIT方案(例如,evaluates)尝试在计算函数之前找到参数的值;因此,首先输入pt-t1,这导致我们以非尾部递归的方式首先进入基本情况,因为我们还没有调用display etc:再次输入了替代项less if,if>0 display 0 pt-0 1,此时缺少替代项子句会导致if表单返回未指定的值,同样,使用此值时会导致错误

;;bad
(define (pt t)
   (if (> t 0)
       (pt (- t 1)))
   (display t))
很好,事实上:首先从一个数字t开始倒计时到0,然后在从递归返回的过程中打印它们,即打印一个从0到t的递增序列。不是尾部递归

;;good
(define (pt t)
   (if (> t 0)
       (pt (- t 1))))
;;bad
(define (pt t)
   (if (> t 0)
       ((pt (- t 1)))))
当给定一个数字时,当倒计时到0时,它什么也不做,只是终止。尾部递归

;;good
(define (pt t)
   (if (> t 0)
       (pt (- t 1))))
;;bad
(define (pt t)
   (if (> t 0)
       ((pt (- t 1)))))
确实不好,;尝试调用pt-t1的结果,因此不是尾部递归,但此结果不是函数:在倒计时到0后,if缺少替代项,因此再次返回一个未指定的值。麻省理工学院的计划说:;对象[未指定的返回值]不适用。guile应该说类似的话;请务必在SO问题中包含具体测试和完整错误消息

最后一个

(define (pt t)
   (define (qt t)
      (display t)
      (pt (- t 1)))
   (if (> t 0)
       (qt t)))
不在每次调用时定义qt;它只定义一次,定义后作为pt的内部过程,因此您可以直接内联它:

(define (pt t)
   (if (> t 0)
       (begin (display t)
              (pt (- t 1)))))
这会再次打印所有降序数字,但不会打印0

你在这里的主要经验是总是在if表单中包含替换子句,以及测试和结果。而且,不要使用误导性的缩进


如果您对这些代码片段中的任何一个有特定的问题,请针对每个代码片段提出一个新的、单独的问题。

您能否更具体地说明调用过程的参数以获取错误?当您看到pt。。。你最好确保程序确实返回了一个程序。谢谢,你已经澄清了我的问题。我之所以失明,是因为我仍然像在程序语言中那样思考if‘falling-thru’。@ClaudeGWilbur但这是一种程序语言,它的if将失败,如果有什么东西要失败,即if不是最后一个表达式时。最好在上面单独发布一个关于一个单独代码段的问题,以便澄清。这样,误解的机会就少了。此外,如果答案中有一个,请务必接受其中最有帮助的答案:。