在列表中搜索整数(Lisp)

时间:2013-09-22 00:46:02

标签: lisp common-lisp

我想不出一种搜索列表的方法,以确保它具有所有整数。如果有非整数数据,我想立即返回nil,如果没有则继续我的功能。

我要尝试的递归函数将cons car与列表的cdr进行对比。通过我的尝试,我无法返回nil。我只能忽略非整数数据。例如,(add-1-all '(1 2 3 a))将在为每个数字添加一个后返回(2 3 4)

    (defun add-1-all (L) 
            (if (null L) 
                L
              (if (integerp (car L))
                  (cons (+ (car L) 1) (add-1-all (cdr L)))
                  nil)))

我确实理解这种情况正在发生,因为递归正在添加到列表中。

2 个答案:

答案 0 :(得分:4)

你的第一句话,

  

我想不出一种在Lisp中搜索列表的方法,以确保它具有所有整数。

听起来像是要检查列表是否全部是整数。您可以检查使用every列表是否全部是整数:

CL-USER> (every 'integerp '(1 2 3 4))
;=> T
CL-USER> (every 'integerp '(1 2 a 4))
;=> NIL

every将负责短路,即在第一个元素发现谓词失败后返回nil

但是,您的代码听起来像是要映射到列表,收集应用于每个整数的函数的值并返回收集的值,除非遇到非整数,否则返回null。也许最简单的方法是使用loop宏。解决方案看起来几乎与英文规范相同:

CL-USER> (loop for x in '(1 2 3 4)
            if (not (integerp x)) return nil
            else collect (1+ x))

;=> (2 3 4 5)
CL-USER> (loop for x in '(1 2 a 4)
            if (not (integerp x)) return nil
            else collect (1+ x))

;=> NIL

使用loop执行此操作与递归解决方案相比也有一些优势。虽然Lisp系列中的某些语言(例如,Schema)需要尾调用优化,而一些Common Lisp实现也需要它,但它在Common Lisp中不是必需的。因此,如果您使用迭代解决方案(例如,使用loop)而不是递归(甚至是尾递归)实现,它可以更安全(例如,您将不会耗尽堆栈空间)。

答案 1 :(得分:1)

关键是使用辅助函数,并且该辅助函数在递归时随身携带答案,以便在必要时随时丢弃整个函数。顺便说一下,这也是tail recursive,这意味着它可以处理非常长的列表,而不会耗尽堆栈空间。

(defun add-1-all (L) 
  (add-1-all-helper L nil))

(defun add-1-all-helper (L answer)
  (if (null L)
    answer
    (if (integerp (car L))
      (add-1-all-helper
        (cdr L)
        (cons (+ (car L) 1) answer)))))