将 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)))))
我正在尝试获取列表的最小值和最大值,并将它们 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)))))