关于用 lisp 替换 while 和 if 语句的问题
Questions about replacing while and if statements with lisp
我想将下面的代码更改为 Lisp 代码,但我总是遇到语法错误。如何修复 if 语句?
int promising(int i)
{
int k = 1;
while (k < i)
{
if (col[i] == col[k] || abs(col[i] - col[k]) == abs(i - k))
return 0;
k++;
}
return 1;
}
下面是我改成Lisp的代码
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))
( abs((setq b (- i k ))))))
(return-from promising 0)))
do (setq k (1+ k)))
(return-from promising 1))
)
我很难把if语句的复杂条件灵活的改成lisp代码
代码中有几处错误。
- 函数调用不正确
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
;; ^^
;; Incorrect
)
还有这里:
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))
;; ^^
;; Incorrect
( abs((setq b (- i k ))))))
;; ^^
;; Incorrect
(return-from promising 0)))
do (setq k (1+ k)))
(return-from promising 1))
)
loop
宏有 2 do
个关键字
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
;; ^^
;; First do
(= ( abs((setq a (- (nth i col) (nth k col)))))
( abs((setq b (- i k ))))))
(return-from promising 0)))
do (setq k (1+ k)))
;; ^^
;; Second do
(return-from promising 1))
)
return-from
被多次使用
return-from
通常不出现在 Common Lisp 代码中,这很像 C goto
,这是开发人员试图避免的。
- 不连贯
setq
定义 a
和 b
(可能是旧代码)
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))\
;; ^^^^^^
;; ??
( abs((setq b (- i k ))))))
;; ^^^^^^
;; ??
- 奇怪的增量方案
(setq k (1+ k))
虽然正确,Common Lisp 程序员将简单地使用增量函数:
(incf k)
- 最终代码
您可能要查找的代码应该与该代码接近:
(defun promising (i)
(let ((k 1))
(loop while (< k i) do
(if (or (= (nth i col) (nth k col))
(= (abs (- (nth i col) (nth k col)))
(abs (- i k ))))
(return-from promising 0))
(incf k))
;; return value
k))
请注意,该代码不等同于 C
版本,因为数据结构完全不同。在C版本中,访问数据会非常快O(1)
。如果你有大量元素 O(n)
,Common Lisp 版本会很慢。如果您用 array/vector.
替换您的列表,您可以快速使用 Common Lisp
你正在做“C-in-Lisp”。尝试直接翻译 C(或者就此而言,C++/Java/C#/Python ...)程序到 Lisp 中通常会导致糟糕的代码,而你应该更好地尝试理解这些问题是如何解决的在 Lisp.
也就是说:
您应该不在顶层使用(setq col <whatever>)
。全局变量使用 defvar
或 defparameter
引入,它们的名称采用 *variable-name*
形式,以区别于其他变量。这是因为它们有不同的范围规则,并且表现不同(即它们不等同于其他语言的全局变量)。特别是,将 setq
与未用 defvar
或 defparameter
声明的变量一起使用是未定义的行为,大多数实现将允许它,但它们随后将创建此全局变量。你通常不想要那个。总结一下:如果你真的需要这个是一个全局变量,要么使用 (defvar *col* (list 0 0 ...))
,要么在你需要的地方使用 (let ((col (list 0 ...))) <more-code>)
。
loop
是一个复杂的结构。这本身就是您必须在 Lisp 之上学习的另一个 mini-language。特别是,如果您想要做的只是“在某些边界之间循环一些变量并在每一步将其递增某个值”,请使用
(从 1 开始循环 k 做 ...) ;;这引入了一个局部变量 k,每一步递增 1,没有上限
(从 1 到 10 循环 k 做...);;相同,但只循环直到 k 达到 10
(从 1 到 10 循环 k 3 do ...)相同,但在每一步将 k 递增 3
其他结构可用。阅读 this section of Practical Common Lisp for a good introduction, and the relevant CLHS section 以获得技术说明和文档。
- 请遵循空格约定,这样更容易阅读。例如,永远不要在它的行上单独放置一个括号(
e.g.
你最后一个括号),并且 ( abs((setq b (- i k ))))
实际上应该写成 (abs ((setq b (- i k))))
(忽略这是不正确的事实,见下文。 ..).至于样式,还需要固定缩进,不要写DEFUN
是大写的,没必要,看起来很奇怪。
- 你不能为了将事物组合在一起而放置额外的括号,括号具有语义意义。特别是,在大多数情况下,调用函数或使用几乎任何特殊运算符都是由
(<operator-name> <first-arg> <second-arg> ... )
完成的。你几乎从来没有 2 个连续的左括号。
- 为什么要在循环中使用
(setq a ...)
和 (setq b ...)
? a
和 b
都没有在其他任何地方声明或使用过。
- 如果要访问列表的特定元素,请不要使用列表,而要使用向量。特别是,对
nth
函数的多次调用通常表明您确实应该使用向量。
您的代码的正确版本,使用了一些 loop
工具,并且仍然假设 col
是一个列表(不应该是),尽管会有其他循环构造使它成为更清楚...
(defun promising (i)
(loop for k from 1 below i
for col-k = (nth k col)
do (when (or (= (nth i col) (nth k col))
(= (abs (- (nth i col) (nth k col)))
(abs (- i k))))
(return-from promising 0)))
1)
请注意,这段代码 效率极低 这就是为什么我建议不要直接从 C 翻译成 Lisp。特别是,虽然您遍历了一个列表(您在 k-th 步骤访问了 k-th 元素),但您的代码在每一步都调用了 nth
而不是遍历列表!您还在每一步计算 (nth i col)
,这在 C 中已经无用(它是常量,因此不需要在每一步都重新计算),但在这里是灾难性的。这真的应该是:
(defun promising (i)
(let ((col-i (nth i col)))
(loop for k from 1 below i
for col-k in (cdr col) ;; you start from the index 1, not 0
do (when (or (= col-i col-k)
(= (abs (- col-i col-k))
(abs (- i k))))
(return-from promising 0))))
1)
我想将下面的代码更改为 Lisp 代码,但我总是遇到语法错误。如何修复 if 语句?
int promising(int i)
{
int k = 1;
while (k < i)
{
if (col[i] == col[k] || abs(col[i] - col[k]) == abs(i - k))
return 0;
k++;
}
return 1;
}
下面是我改成Lisp的代码
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))
( abs((setq b (- i k ))))))
(return-from promising 0)))
do (setq k (1+ k)))
(return-from promising 1))
)
我很难把if语句的复杂条件灵活的改成lisp代码
代码中有几处错误。
- 函数调用不正确
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
;; ^^
;; Incorrect
)
还有这里:
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))
;; ^^
;; Incorrect
( abs((setq b (- i k ))))))
;; ^^
;; Incorrect
(return-from promising 0)))
do (setq k (1+ k)))
(return-from promising 1))
)
loop
宏有 2do
个关键字
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
;; ^^
;; First do
(= ( abs((setq a (- (nth i col) (nth k col)))))
( abs((setq b (- i k ))))))
(return-from promising 0)))
do (setq k (1+ k)))
;; ^^
;; Second do
(return-from promising 1))
)
return-from
被多次使用
return-from
通常不出现在 Common Lisp 代码中,这很像 C goto
,这是开发人员试图避免的。
- 不连贯
setq
定义a
和b
(可能是旧代码)
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))\
;; ^^^^^^
;; ??
( abs((setq b (- i k ))))))
;; ^^^^^^
;; ??
- 奇怪的增量方案
(setq k (1+ k))
虽然正确,Common Lisp 程序员将简单地使用增量函数:
(incf k)
- 最终代码
您可能要查找的代码应该与该代码接近:
(defun promising (i)
(let ((k 1))
(loop while (< k i) do
(if (or (= (nth i col) (nth k col))
(= (abs (- (nth i col) (nth k col)))
(abs (- i k ))))
(return-from promising 0))
(incf k))
;; return value
k))
请注意,该代码不等同于 C
版本,因为数据结构完全不同。在C版本中,访问数据会非常快O(1)
。如果你有大量元素 O(n)
,Common Lisp 版本会很慢。如果您用 array/vector.
你正在做“C-in-Lisp”。尝试直接翻译 C(或者就此而言,C++/Java/C#/Python ...)程序到 Lisp 中通常会导致糟糕的代码,而你应该更好地尝试理解这些问题是如何解决的在 Lisp.
也就是说:
您应该不在顶层使用
(setq col <whatever>)
。全局变量使用defvar
或defparameter
引入,它们的名称采用*variable-name*
形式,以区别于其他变量。这是因为它们有不同的范围规则,并且表现不同(即它们不等同于其他语言的全局变量)。特别是,将setq
与未用defvar
或defparameter
声明的变量一起使用是未定义的行为,大多数实现将允许它,但它们随后将创建此全局变量。你通常不想要那个。总结一下:如果你真的需要这个是一个全局变量,要么使用(defvar *col* (list 0 0 ...))
,要么在你需要的地方使用(let ((col (list 0 ...))) <more-code>)
。loop
是一个复杂的结构。这本身就是您必须在 Lisp 之上学习的另一个 mini-language。特别是,如果您想要做的只是“在某些边界之间循环一些变量并在每一步将其递增某个值”,请使用(从 1 开始循环 k 做 ...) ;;这引入了一个局部变量 k,每一步递增 1,没有上限 (从 1 到 10 循环 k 做...);;相同,但只循环直到 k 达到 10 (从 1 到 10 循环 k 3 do ...)相同,但在每一步将 k 递增 3
其他结构可用。阅读 this section of Practical Common Lisp for a good introduction, and the relevant CLHS section 以获得技术说明和文档。
- 请遵循空格约定,这样更容易阅读。例如,永远不要在它的行上单独放置一个括号(
e.g.
你最后一个括号),并且( abs((setq b (- i k ))))
实际上应该写成(abs ((setq b (- i k))))
(忽略这是不正确的事实,见下文。 ..).至于样式,还需要固定缩进,不要写DEFUN
是大写的,没必要,看起来很奇怪。 - 你不能为了将事物组合在一起而放置额外的括号,括号具有语义意义。特别是,在大多数情况下,调用函数或使用几乎任何特殊运算符都是由
(<operator-name> <first-arg> <second-arg> ... )
完成的。你几乎从来没有 2 个连续的左括号。 - 为什么要在循环中使用
(setq a ...)
和(setq b ...)
?a
和b
都没有在其他任何地方声明或使用过。 - 如果要访问列表的特定元素,请不要使用列表,而要使用向量。特别是,对
nth
函数的多次调用通常表明您确实应该使用向量。
您的代码的正确版本,使用了一些 loop
工具,并且仍然假设 col
是一个列表(不应该是),尽管会有其他循环构造使它成为更清楚...
(defun promising (i)
(loop for k from 1 below i
for col-k = (nth k col)
do (when (or (= (nth i col) (nth k col))
(= (abs (- (nth i col) (nth k col)))
(abs (- i k))))
(return-from promising 0)))
1)
请注意,这段代码 效率极低 这就是为什么我建议不要直接从 C 翻译成 Lisp。特别是,虽然您遍历了一个列表(您在 k-th 步骤访问了 k-th 元素),但您的代码在每一步都调用了 nth
而不是遍历列表!您还在每一步计算 (nth i col)
,这在 C 中已经无用(它是常量,因此不需要在每一步都重新计算),但在这里是灾难性的。这真的应该是:
(defun promising (i)
(let ((col-i (nth i col)))
(loop for k from 1 below i
for col-k in (cdr col) ;; you start from the index 1, not 0
do (when (or (= col-i col-k)
(= (abs (- col-i col-k))
(abs (- i k))))
(return-from promising 0))))
1)