Recursion Lisp:如何打印递归函数以打印列表和子列表中的每个项目(不带引号),并返回项目数?

Recursion Lisp:如何打印递归函数以打印列表和子列表中的每个项目(不带引号),并返回项目数?,recursion,lisp,common-lisp,Recursion,Lisp,Common Lisp,我希望我的函数打印列表和子列表中的每个项目,不带引号,并返回项目数。列表的输出也需要有序,但我的函数是反向打印。我不知道为什么,有什么原因吗?对于如何递归计算项目数量并返回该数字,有什么建议吗?另外,为什么最后打印的项目应该是9.99而不是100.999 编辑:谢谢你到目前为止的帮助。最后一个问题:有没有办法让像DAY这样的输出用小写(DAY)表示,或者这是不可能做到的 我的职能: (defun all-print (inlist) (cond ((not (listp

我希望我的函数打印列表和子列表中的每个项目,不带引号,并返回项目数。列表的输出也需要有序,但我的函数是反向打印。我不知道为什么,有什么原因吗?对于如何递归计算项目数量并返回该数字,有什么建议吗?另外,为什么最后打印的项目应该是9.99而不是100.999

编辑:谢谢你到目前为止的帮助。最后一个问题:有没有办法让像DAY这样的输出用小写(DAY)表示,或者这是不可能做到的

我的职能:

(defun all-print (inlist)
    (cond
        ((not (listp inlist)) 
            (format t "Error, arg must be a list, returning nil")
            ())          
        ((null inlist) 0) 
        ((listp (car inlist)) 
            (ffn (append (car inlist)(cdr inlist))))
        (t
            (format t "~a " (car inlist) (ffn (cdr inlist))))))  
(defun print-all (list)
  (reduce '+ list
          :key (lambda (x)
                 (if (listp x)
                     (print-all x)
                     (prog1 1
                       (format t "~A " x))))))
(defun all-print (lst)
  (if (null lst)
    0                    ; empty list => length is 0
    (let ((c (car lst))) ; bind first element to c
      (if (listp c)      ; if it's a list
        (+ (all-print c) (all-print (cdr lst))) ; recurse down + process the rest of the list
        (progn           ; else
          (format t "~a " c)              ; not a list -> print item, then
          (1+ (all-print (cdr lst)))))))) ; add 1 and process the rest of the list
我的输出示例:

CL-USER 1 >  (all-print (list 5 "night" 3 (list 9 -10) (quote day) -5.9 (* 100.999)))
100.999 -5.9 DAY -10 9 3 night 5 
NIL
5 night 3 9 -10 day -5.9 9.99 ;print
8 ;returns
假设输出的内容示例:

CL-USER 1 >  (all-print (list 5 "night" 3 (list 9 -10) (quote day) -5.9 (* 100.999)))
100.999 -5.9 DAY -10 9 3 night 5 
NIL
5 night 3 9 -10 day -5.9 9.99 ;print
8 ;returns

它看起来像是
所有的print
都应该被调用
ffn
,因为它看起来像是递归调用。在这个答案的其余部分,我将使用
ffn
,因为它比较短

为什么输出是相反的 目前,您的final
cond
子句在进行任何打印之前进行递归调用,因为您的递归调用是
format
的参数:

(format t "~a " (car inlist) (ffn (cdr inlist)))
;               ------------ -----------------
;                     3rd          4th
在调用format之前,将对
format
的所有参数(包括本例中的第4个)进行求值。这里的第4个参数将打印列表的其余部分,然后
format
将最终打印列表的第一个元素。最后一个
cond
子句应该进行打印,然后进行递归调用:

(cond 
  …
  (t
    (format t "~a " (car inlist))
    (ffn (cdr inlist))))
为什么你得到的是100.999而不是9.99 您在输出中得到的是100.999,而不是9.99(或接近它的值),因为
(*100.999)
的值只是
100.999
的值。我猜您想要
(*10 0.999)
(注意
10
0.99
之间的空格)。不过,由于浮点运算的原因,这仍然不会达到9.99,但会很接近

如何获得打印的元素数 这里提供了一个很好的解决方案。如果要返回打印的元素数,那么此函数的每个返回值都应该是一个数字。你有四个案子

  • 不是列表-返回
    nil
    不是一个好主意。如果无法返回数字(如0),则发出实际错误信号(如使用
    (错误“~a不是列表中的列表)”
  • inlist为空-返回0(您已经这样做了)
  • (car-inlist)
    是一个列表-在这里您对
    ffn
    进行递归调用。因为合同上说它将返回一个计数,所以您就没事了。这是它在第一种情况下如此重要的原因之一(不是列表)您不返回非号码;合同取决于每个返回号码的呼叫
  • 在最后一种情况下,您打印一个项目,然后对
    ffn
    进行递归调用。该递归调用返回打印的剩余元素数,并且由于您刚刚打印了一个,因此您需要向其中添加一个。因此,final
    cond
    子句实际上应该如下所示。(向某个对象添加一个对象非常常见,以至于common Lisp有一个函数。)

更有效的解决方案 我们已经用您的原始代码解决了这些问题,但是我们也可以询问是否有更好的方法来解决这个问题

不要附加 请注意,当您输入类似于
((ab c)de f)
的内容时,您可以创建列表
(ab c d e f)
,并在其上递归。但是,您可以在
(ab c)
(de f)
上等价地递归,并将结果添加在一起。这样可以避免使用
append
创建新列表

不要检查参数类型 您正在检查输入是否是一个列表,但实际上不太需要这样做。如果输入不是列表,则对其使用列表处理函数将发出类似错误的信号

新版本 这有点类似于,但我对如何处理某些事情做了一些不同的选择。我使用一个本地函数
process element
来处理每个输入列表中的元素。如果元素是一个列表,那么我们递归地将其传递给
print all
,并返回递归调用的结果。否则,我们返回one并打印值。(我使用
(prog1 1…
强调我们返回一个,而打印只是一个副作用。
print all
的主要部分现在是一个典型的递归

(defun print-all (list)
  (flet ((process-element (x)
           (if (listp x)
               (print-all x)
               (prog1 1
                 (format t "~A " x)))))
    (if (endp list)
        0
        (+ (process-element (first list))
           (print-all (rest list))))))
当然,现在我们已经拉出了辅助函数,迭代更清晰了,我们看到这实际上是一个例子。您甚至可以选择取消局部函数,只使用lambda函数:

(defun all-print (inlist)
    (cond
        ((not (listp inlist)) 
            (format t "Error, arg must be a list, returning nil")
            ())          
        ((null inlist) 0) 
        ((listp (car inlist)) 
            (ffn (append (car inlist)(cdr inlist))))
        (t
            (format t "~a " (car inlist) (ffn (cdr inlist))))))  
(defun print-all (list)
  (reduce '+ list
          :key (lambda (x)
                 (if (listp x)
                     (print-all x)
                     (prog1 1
                       (format t "~A " x))))))
(defun all-print (lst)
  (if (null lst)
    0                    ; empty list => length is 0
    (let ((c (car lst))) ; bind first element to c
      (if (listp c)      ; if it's a list
        (+ (all-print c) (all-print (cdr lst))) ; recurse down + process the rest of the list
        (progn           ; else
          (format t "~a " c)              ; not a list -> print item, then
          (1+ (all-print (cdr lst)))))))) ; add 1 and process the rest of the list

以下是我对如何编写此函数的建议:

(defun all-print (inlist)
    (cond
        ((not (listp inlist)) 
            (format t "Error, arg must be a list, returning nil")
            ())          
        ((null inlist) 0) 
        ((listp (car inlist)) 
            (ffn (append (car inlist)(cdr inlist))))
        (t
            (format t "~a " (car inlist) (ffn (cdr inlist))))))  
(defun print-all (list)
  (reduce '+ list
          :key (lambda (x)
                 (if (listp x)
                     (print-all x)
                     (prog1 1
                       (format t "~A " x))))))
(defun all-print (lst)
  (if (null lst)
    0                    ; empty list => length is 0
    (let ((c (car lst))) ; bind first element to c
      (if (listp c)      ; if it's a list
        (+ (all-print c) (all-print (cdr lst))) ; recurse down + process the rest of the list
        (progn           ; else
          (format t "~a " c)              ; not a list -> print item, then
          (1+ (all-print (cdr lst)))))))) ; add 1 and process the rest of the list
然后