检查列表是否是lisp中的所有数字

时间:2016-10-04 03:02:08

标签: lisp common-lisp

所以我有一个程序:

(defun add (L)
  (cond((endp L) nil)
       (t(cons(1+(first L)))(add(rest L)))))

将为列表的每个成员添加1。我想检查列表是否都是数字,如果没有,则返回nil,并且不知道如何在defun中执行此操作。

我想过做

(defun add (L)
  (cond((endp L) nil)
       ((not(numberp(first L))) nil)
       (t(cons(1+(first L)))(add(rest L)))))

但如果非数字位于中间,那么仍将返回列表的开头。我如何预先检查并在开始时返回零?

5 个答案:

答案 0 :(得分:4)

您可以将其打包在condition-case

(defun add (L)
  (condition-case nil
      (mapcar '1+ L)
    (error nil)))

答案 1 :(得分:3)

另一种可能性是使用迭代:

(defun add (l)
  (loop for x in l 
     if (numberp x) 
     collect (1+ x) 
     else do (return-from add nil)))

在第一个非数字元素上使用nil立即退出该函数。

答案 2 :(得分:3)

您不会使用递归实现迭代,因为Lisp已经提供了迭代结构。示例:MAPCAR

Common Lisp还提供了像RETURN-FROM这样的控制流结构,您可以从返回。由DEFUN定义的函数具有名称的块,BLOCK也可以显式创建命名块。两者的例子:

CL-USER 62 > (block mapping
               (mapcar (lambda (item)
                         (if (numberp item)
                             (1+ item)
                           (return-from mapping nil)))
                       '(1 2 3 nil 5 6)))
NIL

CL-USER 63 > (block mapping
               (mapcar (lambda (item)
                         (if (numberp item)
                             (1+ item)
                           (return-from mapping nil)))
                       '(1 2 3 4 5 6)))
(2 3 4 5 6 7)

作为功能:

CL-USER 64 > (defun increment-list (list)
               (mapcar (lambda (item)
                         (if (numberp item)
                             (1+ item)
                           (return-from increment-list nil)))
                       list))
INCREMENT-LIST

CL-USER 65 > (increment-list '(1 2 3 4 5 6))
(2 3 4 5 6 7)

CL-USER 66 > (increment-list '(1 2 3 nil 5 6))
NIL

答案 3 :(得分:2)

我会说,在Common Lisp中,检查列表中的所有元素都是数字的惯用方法是(every #'numberp the-list),所以我可能会把它写成:

(defun add-1 (list)
   (when (every #'numberp list)
      (mapcar #'1+ list)))

可以使用(if ...)(and ...),但在这种情况下,我认为(when ...)可以提供最清晰的代码。

答案 4 :(得分:1)

难点在于传播nil导致列表末尾的nil导致所有内容都为nil。一种解决方案是检查add是否返回nil,但(rest xs)不是nil。但是,IMO可以更简单地迭代列表两次,第一次检查数字,然后在第二次迭代时进行加法。

试试这个:

(defun add (xs) 
   (cond ((endp xs) nil) 
         ((not (numberp (car xs))) nil) 
         (t (let ((r (add (rest xs)))) 
                 (cond ((and (not r) (rest xs)) nil) 
                 (t (cons (1+ (first xs)) r)))))))

除非出现错误,否则会导致:

(add '()) => nil

(add '(1 2)) => '(2 3)

(add '(x y)) => nil

(add '(1 2 y)) => nil

编辑:没有let。这会导致2^(n+1)-1调用add来获取长度为n的列表。

(defun add (xs) 
   (cond ((endp xs) nil) 
         ((not (numberp (car xs))) nil) 
         (t (cond ((and (not (add (rest xs))) (rest xs)) nil) 
                  (t (cons (1+ (first xs)) (add (rest xs)))))))))