我希望我的函数打印列表和子列表中没有引号的每个项目,并返回项目数。列表的输出也需要按顺序排列,但我的功能是反向打印。我不知道为什么,有什么原因吗?有关如何递归计算项目数量并返回该数字的任何建议?另外,为什么最后打印的项目应该是9.99而不是100.999?
编辑:感谢您的帮助到目前为止。最后一个问题:有没有办法让像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))))))
我的输出示例:
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
答案 0 :(得分:2)
看起来all-print
应该被称为ffn
,因为它看起来应该是递归调用。在本回答的其余部分中,我将使用ffn
,因为它更短。
目前,您的最终cond
子句在进行任何打印之前进行递归调用,因为您的递归调用是format
的参数:
(format t "~a " (car inlist) (ffn (cdr inlist)))
; ------------ -----------------
; 3rd 4th
format
的所有参数,包括本例中的第4个参数,都会在调用format之前进行评估。这里的第四个参数将打印列表的 rest ,然后format
将最终打印列表的第一个元素。您的上一个cond
子句应该进行打印,然后进行递归调用:
(cond
…
(t
(format t "~a " (car inlist))
(ffn (cdr inlist))))
你的输出中得到100.999而不是9.99(或接近它的东西),因为(* 100.999)
的值只是100.999
的值。我猜你想要(* 10 0.999)
(注意10
和0.99
之间的空格)。然而,由于浮点运算,它仍然不会很9.99
,但它会很接近。
uselpa's answer在这里提供了一个很好的解决方案。如果您应该返回打印的元素数,那么此函数的每个返回值都应该是一个数字。你有四个案例,
nil
不是一个好主意。如果这不能返回一个数字(例如,0),则发出实际错误信号(例如,使用(error "~A is not a list" inlist)
。(car inlist)
是一个列表 - 在这里您对ffn
进行递归调用。由于合同说它将返还一个计数,你没事。这是在第一种情况(不是列表)中如此重要的原因之一,即您不返回非数字;合同取决于每个返回一个号码的电话。在最后一种情况下,您打印一个项目,然后对ffn
进行递归调用。该递归调用返回打印的剩余元素的数量,并且由于您只打印了一个元素,因此需要向其中添加一个元素。因此,最终的cond
子句实际上应该类似于以下内容。 (添加一个东西是如此常见,以至于Common Lisp具有1+
功能。)
(cond
…
(t
(format t "~a " (car inlist))
(1+ (ffn (cdr inlist))))) ; equivalent to (+ 1 (ffn (cdr inlist)))
我们已经解决了您原始代码的问题,但我们也可以询问是否有更好的方法来解决问题。
请注意,当您输入((a b c) d e f)
时,您可以创建列表(a b c d e f)
并对其进行递归。但是,您可以在(a b c)
和(d e f)
上等效递归,并将结果一起添加。这样可以避免使用append
创建新列表。
您正在检查输入是否为列表,但实际上并不需要这么做。如果输入不是列表,则使用列表处理功能将发出类似的错误信号。
这有点类似于uselpa's answer,但我对如何处理某些事情做了一些不同的选择。我使用本地函数process-element
来处理每个输入列表中的元素。如果元素是一个列表,那么我们递归地将它传递给print-all
,并返回递归调用的结果。否则我们返回一个并打印该值。 (我使用(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))))))
当然,既然我们已经取出了辅助函数,那么迭代会更加清晰,我们发现它实际上是reduce
的情况。你甚至可以选择取消本地函数,只使用lambda函数:
(defun print-all (list)
(reduce '+ list
:key (lambda (x)
(if (listp x)
(print-all x)
(prog1 1
(format t "~A " x))))))
答案 1 :(得分:0)
以下是关于如何编写此功能的建议:
(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
然后
? (all-print (list 5 "night" 3 (list 9 -10) (quote day) -5.9 (* 100.999)))
5 night 3 9 -10 DAY -5.9 100.999
8