定义功能' occ'采用列表L和符号A并计算L中符号A的出现。 例: (occ'(((s)o)d)' f) - > 0
到目前为止我得到了什么:
(defun occ(list a)
(setq counter 0)
;Checks if the given list is has an nested list
(if (consp list)
; Breaking the list down atom by atom and recursing
(or (occ a (car list))
(occ a (cdr list)))
; checks if symbols are the same
(if(eq a list)
(setq counter(1+ counter)))))
但是我的输出继续说Nil而不是显示计数器值。 我不能使用任何更高级别的LISP功能。
答案 0 :(得分:6)
首先,不要在你的函数中使用setq进行变量初始化,使用let
。其次,让我们看看为什么你做错了,你的代码:
(defun occ(list a)
(setq counter 0) ;; You always setting counter to 0 on new
;; level of recursion
(if (consp list)
(or (occ a (car list)) ;; You reversed arguments order?
(occ a (cdr list))) ;; according to your definition it must be
;; (occ (car list) a)
(if(eq a list)
(setq counter(1+ counter)))))
无论如何,你不需要任何计数器变量来做你想做的事。
正确的函数可能看起来像这样(我更改了参数顺序,因为我在LIST中找到SYMBOL看起来更好):
(defun occ (sym nested-list)
(cond
((consp nested-list)
(+ (occ sym (car nested-list)) (occ sym (cdr nested-list))))
((eq sym nested-list) 1)
(t 0)))
CL-USER> (occ 'x '(((s) o ((f ()) f)) d))
0
CL-USER> (occ 'f '(((s) o ((f (x (((f))))) f)) d f))
4
答案 1 :(得分:1)
如果您将定义提供给SBCL:
; in: DEFUN OCC
; (SETQ COUNTER 0)
;
; caught WARNING:
; undefined variable: COUNTER
;
; compilation unit finished
; Undefined variable:
; COUNTER
; caught 1 WARNING condition
因此,您正在修改全局未定义变量counter
。该功能何时返回?好吧,或者会使用nil
或car
返回递归的第一次非cdr
返回。什么返回值?当它不是缺点时,它会在符号匹配时评估为incf
计数器的中间值,或者当它不匹配时评估为nil
。
尝试这样做:
(defun occ (list a &optional (counter 0))
(cond ((equal list a) (1+ counter))
((atom list) counter)
(t (occ (cdr list)
a
(occ (car list)
a
counter)))))
计数器是一个可选的累加器,用于保存值。由于它已经通过,因此它不会在递归调用之间共享,而是在每次调用时替换为更新后的值,使其功能强大且易于遵循。当您需要同时搜索car
和cdr
时,您使用此阶段的计数器递归car
,并且返回值将用作cdr
中的计数器。对于atom的列表,如果实现支持它,那么它将是尾递归的。这支持将符号作为列表的尾部进行查找。例如。 (occ '((x . x) . x) 'x) ; ==> 3
如果您确定没有点列表(每个列表都没有终止),您可以使用loop
宏:
(defun occ (list a)
(loop :for e :in list
:counting (equal e a) :into count
:if (consp e)
:summing (occ e a) :into sum
:finally (return (+ count sum))))
;; tests
(occ '(x (x x (x (x ) x)) y z) 'y) ; ==> 1
(occ '(x (x x (x (x ) x)) y z) 'x) ; ==> 6
(occ '((x . x) . x) 'x) ; ERROR like "A proper list must not end with X".