为什么递归函数中的计数总是需要两个参数?

时间:2019-08-01 00:15:26

标签: recursion scheme lisp

我用递归和循环宏编写了一些简单的循环,但令我困扰的是,向上计数需要两个参数,而向下计数则不需要。

是否存在示例?

这个问题的开始只是如何打印递增的内容。我的第一个功能是“ printsomestuff”。

(defun printsomestuff (stuff times) 
  (if (= times 0)
      'im-the-return-value
      (progn 
        (print stuff)
        (printsomestuff stuff (1- times)))))

(defun counting-down (topnumber)
  (if (= topnumber 0)
      'done
      (progn 
        (print topnumber)
        (counting (- topnumber 1)))))


(defun loopcounting (uptonumber)
  (loop for i from 1 to uptonumber
    do (print i)))

(defun recurcounting-up (uptonumber)
  (let ((incrementer 0))
    (if  
     (= incrementer uptonumber)
     'done
     (progn 
       (print incrementer)
       (recurcounting-up (+ incrementer 1))))))

(defun recur-counting-up-two (uptonumber startnumber)
  (if (> startnumber uptonumber)
      'done
      (progn
        (print startnumber)
        (recur-counting-up-two uptonumber (+ startnumber 1)))))

递归递增计数以0无限循环,因为每次函数调用时都会重置增量器。那不是我想要的。

3 个答案:

答案 0 :(得分:7)

无论您是递增还是递减都没有关系。问题是递归的基本情况是可以在函数中进行硬编码还是需要作为参数提供。在倒数示例中,您总是以0结尾,因此它不必是参数-您只需为当前数字指定一个参数。但是在您的递增计数示例中,结束号无法放入代码中,因此需要将其作为第二个参数。

如果您一直计数到100,则可以像倒数示例一样编写代码。同样,如果您想倒数到任意数字,而不仅仅是0,则需要两个参数。

答案 1 :(得分:1)

要补充一下Barmar所说的内容(his answer确实回答了这个问题,实际上是对它的评论),如果您使用局部函数,那么您可以 使递归函数仅具有一个参数。您甚至可以按照适当的方向进行计数。但这只是一个技巧:如果基本情况或某些递归步骤不固定(即不一定总是01-说),那么您将必须提供它们。

在CL中沿任一方向计数:

(defun count/printing (from to)
  (let ((next (if (< from to) #'1+ #'1-)))
    (labels ((count (i)
               (print i)
               (if (= i to)
                   i
                 (count (funcall next i)))))
      (count from))))

和Racket中,它成为Lisp-1并命名为let,因此更加优雅:

(define (count/printing from to)
  (define next (if (< from to) add1 sub1))
  (let count ([i from])
    (displayln i)
    (if (= i to)
        i
        (count (next i)))))

答案 2 :(得分:0)

考虑到tfb的答案后,我的解决方案如下所示。

(defun recur-counting-up-two (uptonumber startnumber)
  (if (> startnumber uptonumber)
      'done
      (progn
        (print startnumber)
        (recur-counting-up-two uptonumber (+ startnumber 1)))))
(defun count-up (uptonumber)
  (recur-counting-up-two uptonumber 0))

它只是创建第二个顶级包装器函数,其中一个参数以硬编码形式传递。 尽管tfb的答案似乎更紧凑,但我发现它从远处更易读。减少中心嵌入对于使用可读性已经过分的语言来说总是一件好事。