将 LET 变量绑定到 Lisp 中的新值

Binding LET variables to new values in CLisp

我正在尝试获取列表的最小值和最大值,并将它们 return 作为缺点。

;;
;; Find minimum and maximum of a list
;;
(defun min-max (l)
  (let ((n 0) (min 0) (max 0) (size (numAtomsInList l)))
    (loop (when (= n (- size 1)) (return))
      (cond
        ((> (nth n l) (nth (+ n 1) l))) (setq min 5) ;(nth n l)) 
        ((< (nth n l) (nth (+ n 1) l))) (setq max 7) ;(nth n l))  
        (t (setq max n))
      )
      (incf n)
    )
    (cons min max)
  )
)

当 运行 函数在最小和最大变量之前没有 SETQ 时,它编译正常,但我得到结果 (0 . 0) - 在 LET 中设置的原始值。使用 SETQ,它给了我错误:

错误:试图获取未绑定变量“SETQ”的值。

当我遍历列表时,我还能如何更改 min 和 max 的值?为什么 SETQ 在句法上是正确的却假设它是一个变量?

我认为您在 cond 正文中对表格的分组不正确。 cond 子句应类似于 (CONDITION BODY);你有

(cond
  ((> (nth n l) (nth (+ n 1) l)))
  (setq min 5)
  ;; etc
  )

而你想要

(cond
  ((> (nth n l) (nth (+ n 1) l))
   (setq min 5))
  ;; etc
  )

如果您有 Clojure 背景,您会发现许多 Common Lisp 形式的分组与其 Clojure 类似物不同。

如果您遇到类似

的情况,请详细说明您所看到的确切错误的原因
(cond
  (setq x y))

cond 将尝试将 setq 作为一个值来求值,而不是作为一个函数(回想一下,在 Common Lisp 中,符号可以同时具有函数和值绑定);这与写 (when setq x y) 相同,如果我们将一个值绑定到 setq,我们将不再出现未绑定变量错误。

? (let ((setq t) (x :x) (y :y)) (cond (setq x y)))
:Y

除了Huw指出的问题外,你的代码还有一个严重的效率问题:它使用了nth,每次都需要遍历整个列表;实际上,您正在编写二次算法。作为一般经验法则,除非您真的知道自己在做什么,否则不应将 nth 与可变参数一起使用。

为了提高效率,您应该按顺序遍历输入列表,不要从头开始。如果像我一样,你是个老屁,你可以使用 do 循环:

(defun min-max (l)
  (let ((min (car l)) (max (car l)))
    (do ((l (cdr l) (cdr l)))
        ((null l) (cons min max))
      (when (< (car l) min) (setq min (car l)))
      (when (> (car l) max) (setq max (car l))))))

如果您愿意,可以使用花哨的 loop 东西:

(defun min-max (l)
  (let ((min (car l)) (max (car l)))
    (loop for e in (cdr l)
          do (when (< e min) (setq min e))
          do (when (> e max) (setq max e)))
    (cons min max)))

或者,Scheme 风格,你可以使用尾递归(忽略那些告诉你它不可移植的老 Common Lisp 程序员):

(defun min-max-3 (l)
  (let ((min (car l)) (max (car l)))
    (labels
        ((mm (l)
           (cond ((null l) (cons min max))
                 (t (when (< (car l) min) (setq min (car l)))
                    (when (> (car l) max) (setq max (car l)))
                    (mm (cdr l))))))
      (mm (cdr l)))))