用do循环不能在lisp中求和

时间:2016-12-09 18:55:11

标签: lisp common-lisp

(defun suma (L)
  (setq var 0)
  (do 
      ((i 0 (+ i 1)))
      ((= i (length L)))
    (+ var (nth i L)))
  var)

为什么它总是返回0?

它不应该返回列表L的总和吗?

2 个答案:

答案 0 :(得分:2)

info on how to do a good post不会修改其参数,因此,由于您永远不会修改df <- read.csv.sql("sample.csv", "select *, strftime('%d/%m/%Y', Date) as DateFormated from file where DateFormatted >= 1/2/2007 and DateFormatted <= 2/2/2007 ", sep=";") ,因此会返回其初始值0。

您需要将var替换为(+ var (nth i L)),等同于(incf var (nth i L))

请参阅+

请注意,您应该将(setq var (+ var (nth i L)))incf绑定,而不是使用let将其设为全局。

最重要的是,请注意您的算法在list参数的长度上是二次(因为setq每次从头开始扫描您的列表。)

以下是一些更好的实现:

var

以下是错误的实施:

(defun sum-1 (l)
  (reduce #'+ l))

(defun sum-2 (l)
  (loop for x in l sum x))

(defun sum-3 (l)
  (let ((sum 0))
    (dolist (x l sum)
      (incf sum x))))

(defun sum-4 (l) (apply #'+ l)) 的问题是,如果提供的列表的长度大于nth,它将失败。

答案 1 :(得分:0)

我认为这将是对完整学习体验的评论,但我无法在评论中加入代码。

有一种方法可以在不修改任何参数的情况下进行求和,这是通过递归方式进行的:

(defun recsum (list)
  (if list
      (+ (first list) (recsum (rest list)))
      0))

此版本可以由编译器进行尾调用,并且与循环一样快:

(defun recsum2 (list &optional (accumulator 0))
  (if list
      (recsum2 (rest list) (+ accumulator (first list)))
      accumulator))

您尝试做的事情可以通过以下do来完成:

(defun suma (l)
  (do 
   ((var 0)
    (i 0 (+ i 1)))
   ((= i (length l)) var)
    (incf var (nth i l))))

但我们通常不会在do的身体做任何事情,所以就像这样:

(defun suma (l)
  (do
   ((i 0 (+ i 1))
    (var 0 (+ var (nth i l))))
   ((= i (length l)) var)))

但是nthlength速度很慢,所以最好这样做:

(defun suma (l)
  (do* 
   ((var (first l) (+ var (first list)))
    (list (rest l) (rest list)))
   ((null list) var)))

这个没有*中的do,并且在空列表中返回0:

(defun suma (l)
  (do 
   ((acc 0 (+ acc (first list)))
    (list l (rest list)))
   ((null list) acc)))

但我最喜欢的是来自@sds的reduce版本,它也可以在空列表中返回0:initial-value 0

编辑:recsum2没有返回任何内容,因此需要修复。