方案中的递归:基本案例和意外错误

时间:2015-01-04 05:00:08

标签: recursion scheme

我是一个计划菜鸟,教我自己的计划是一种更深入理解功能风格和技术的方法。我遇到了递归和基本案例的问题。

有时,当递归到达基本情况时,我会收到意外错误:

ERROR: In procedure #<unspecified>:
ERROR: Wrong type to apply: #<unspecified>

我用不同的方式表达基本情况。我已经发现了足够的工作模式,我总能想出一个符合我意图的咒语。但我真的不明白为什么下面的一些例子失败了,有些成功了。

(define (pt t)
   (display t)
   (if (> t 0)
       (pt (- t 1))))

;;good
(define (pt t)
   (if (> t 0)
       ((display t)
    (pt (- t 1)))))

;;bad
(define (pt t)
   (if (> t 0)
       (pt (- t 1)))
   (display t))

;;good
(define (pt t)
   (if (> t 0)
       (pt (- t 1))))

;;bad
(define (pt t)
   (if (> t 0)
       ((pt (- t 1)))))

;;good
(define (pt t)
   (define (qt t)
      (display t)
      (pt (- t 1)))
   (if (> t 0)
       (qt t)))

这些都是帮助我理解递归机制的玩具程序。我想了解为什么标有;;bad的程序会抛出错误。

我怀疑问题与(if)不是程序有关。如果有人能让我指出正确的方向,我将不胜感激。

我使用的方案是guile 2.0.11

1 个答案:

答案 0 :(得分:2)

一个接一个:

(define (pt t)
   (display t)
   (if (> t 0)
       (pt (- t 1))))

表示显示收到的参数值,然后,如果它是&gt; 0,减少1并重复;别无所求。所以这很好,它甚至是尾递归的;如果给出一个数字,它将打印(尽管没有任何间距)所有递减的数字,直到它达到0.

但由于if形式中没有替代条款,因此最终无法返回。在这种情况下,标准的“未指定”返回值。导致它被退回并不简洁;在这里我们看到它在所有数字打印后返回。但这本身并不是一个错误,只是尝试使用这样的值是一个错误。

;;good
(define (pt t)
   (if (> t 0)
       ((display t)
    (pt (- t 1)))))
这里的缩进是误导性的; ((display t) (pt (- t 1)))表示显示t,然后调用其结果(未定义),就好像它是一个函数(它不是)。坏。 (例如)麻省理工学院计划说:;The object #[unspecified-return-value] is not applicable. - 首先打印1

为什么呢?因为要找出(display t)的返回值,它必须先执行它。但为什么1而不是5(当测试(pt 5)时)?因为要评估(f x),Scheme必须首先找出fx的值,并且它会以某种未指定的顺序执行。

MIT Scheme(例如)在评估函数之前评估(尝试查找参数的值);因此首先输入(pt (- t 1)),它首先引导我们进入基本情况(以非尾递归的方式,因为我们还没有调用display等):再次替代{{1}输入if,此时缺少alternative子句会导致(if (> 0 0) ((display 0) (pt (- 0 1))))形式再次返回“未指定的值”(使用此值时会导致错误)。 / p>

if

好,实际上:首先从数字;;bad (define (pt t) (if (> t 0) (pt (- t 1))) (display t)) 向下计数到0,然后将它们全部打印到从递归返回的路上,即打印从t到{{1}的递增序列}。不是尾递归。

0

什么都不做,而倒数到0(当给出一个数字时),它只是终止。尾递归。

t
确实很糟糕;尝试调用;;good (define (pt t) (if (> t 0) (pt (- t 1)))) 的结果(因此不是尾递归),但是这个结果不是函数:在向下计数到0之后,;;bad (define (pt t) (if (> t 0) ((pt (- t 1))))) 缺少备选,所以再次返回未指明的价值。麻省理工学院计划说:(pt (- t 1))(guile应该说类似的东西;请总是包含具体的测试和完整的错误消息与您的SO问题)。

最后一个

if

在每次调用时都没有定义;The object #[unspecified-return-value] is not applicable.;它只定义一次,作为定义(define (pt t) (define (qt t) (display t) (pt (- t 1))) (if (> t 0) (qt t))) 时的内部过程,所以你可以内联它:

qt

这会再次打印所有降序数字,但不打印0。

这里的主要教训是始终在pt表单中包含替代子句,以及测试和结果。并且,不要使用误导性的缩进。

如果您对这些代码段有任何疑问,请为每个代码片段提出一个新的单独问题。