如何在LISP中将列表中的每个元素递增1

时间:2015-09-20 23:08:39

标签: lisp common-lisp increment

我正在学习LISP,我正在尝试编写一个函数,为列表中的每个元素添加1。我首先测试第一个元素是否为数字,然后将1添加到列表中的第一个元素。然后我递归调用列表其余部分的函数,但是我收到错误。有帮助吗?这是功能:

 (defun add-1-all (L)
    (cond (not (numberp (first L)) nil)
          (t (+1 (first L)) (add-1-all (rest L)))))

4 个答案:

答案 0 :(得分:3)

以下是更多方法:

  1. 在处理列表时(请参阅Joshua的评论),请使用ENDPFIRSTREST,这些广告优先于NULLCARCDR。他们更清楚地传达意图,在ENDP的情况下,检查参数是否是正确的列表。想象一下,你传递了一个用(cons 'a 'b)构建的虚线列表,会发生什么? ENDP检测到列表不正确并发出错误信号。

    (defun add-1-all (list)
      (unless (endp list)
        (cons (1+ (first list))
              (add-1-all (rest list)))))
    
  2. 我使用UNLESS作为NIL值,有些人可能不喜欢。您可能希望在到达列表末尾时明确返回NIL。在这种情况下,请坚持使用COND或只使用IF

    1. 循环。

      (defun add-1-all (list)
        (loop for e in list collect (1+ e)))
      
    2. 让它也适用于数组,而不仅仅是列表。

      (defun add-1-all (sequence)
        (map (type-of sequence) #'1+ sequence))
      

答案 1 :(得分:2)

实现目标的最简单方法是使用地图。 Map将函数应用于序列的每个元素。这样就不需要像处理序列一样处理细节。在下面的代码中,我使用的mapcar仅适用于列表。

(defun add-1 (list)
  (mapcar #'1+ list))

要了解CL提供的其他映射函数(apropos“map”)和使用(describe)来了解更多信息。或者更好地使用clhs search engineextended CL documentation search engine

您提供的解决方案是尝试通过递归解决问题。一般的想法是使用first / rest遍历列表,同时构建一个新元素,其中元素递增1。当列表到达结尾时(您可以使用函数null或endp来测试已到达列表的末尾),应返回新列表。您的解决方案的一个问题是它缺少累加器。你的基本情况(发出停止递归信号的条件)也是错误的。

其他几个指针。使用格式化代码的编辑器,因为它很难阅读。 CL也不是Lisp-1,所以你可以使用list作为变量名,它不会与函数列表冲突。它们具有单独的命名空间。发布错误消息并解释您的解决方案尝试执行的操作或方式也很有帮助。您可能还会发现this textbook对学习Lisp非常有用

答案 2 :(得分:1)

你可以写(+ 1(前L))或(1+(前L)),但你没有写。

此外,您应该使用cons将第一个元素的结果添加到其余元素的结果中。 另外,你真的想在第一个非号码之后放下所有元素吗?或者您是否想要假设所有元素都是数字,在这种情况下您应该了解map或mapcar,它允许您以15个字符解决问题。

答案 3 :(得分:0)

首先你的代码是错误的,如果你编译它会得到几个错误和警告,重要的是一个很好的lisp语法,也知道你在写什么。如果您正在学习lisp,我建议您为slime and quicklisp

提供一个舒适的环境。
; SLIME 2015-06-01; compiling (DEFUN ADD-1-ALL ...)

; file: /tmp/file451NPJ
; in: DEFUN ADD-1-ALL
;     (1 (FIRST L))
; 
; caught ERROR:
;   illegal function call

;     (REST L)
; --> CDR 
; ==>
;   L
; 
; note: deleting unreachable code

;     (COND (NOT (NUMBERP (FIRST L)) NIL) (T (1 (FIRST L)) (ADD-1-ALL (REST L))))
; ==>
;   (IF NOT
;       (PROGN (NUMBERP (FIRST L)) NIL)
;       (COND (T (1 (FIRST L)) (ADD-1-ALL (REST L)))))
; 
; caught WARNING:
;   undefined variable: NOT
; 
; compilation unit finished
;   Undefined variable:
;     NOT
;   caught 1 ERROR condition
;   caught 1 WARNING condition
;   printed 1 note

然后使用递归来执行此任务是个好主意,因为递归对于知道何时停止以及算法的基本情况非​​常重要

在你的情况下,你也可以使用if这两个路径的功能:

(defun add-1-all (list)
  (cond
    ((null list) nil)
    (t (cons (1+ (car list))(add-1-all (cdr list))))))

我建议你尝试使用尾递归函数来实现这一点,以获得更好的性能和良好的学习效果。

同样使用lisp,您可以使用更多功能样式,当时间到来时您将学到这一点,就像在这种情况下使用高阶函数一样,您的函数如下:

;; functional programming higher order functions
(defun add-1-all-ho (list)
  (mapcar #'1+ list))