我构建这个函数来检查是否所有" var"在名单上是数字。 这就是我试图做的事情
(defun check6 (list)
(if (null list) 'TRUE)
(if (not (numberp(first list))) nil)
(check6 (rest list)))
但总是让堆栈溢出。
为什么请?
答案 0 :(得分:10)
堆栈溢出是由于您有几个不相关的if
,因此它们会产生一个未被消耗的值,并且继续来执行其余的主体。功能。这意味着check6
永远不会终止并导致溢出。
如果将代码粘贴到一个自动对齐代码行的编辑器中,您可能会发现编辑器产生了这种对齐:
(defun check6 (list)
(if (null list)
'TRUE) ; only one branch, no else branch, continue to the next form
(if (not (numberp(first list)))
nil) ; again only one branch, continue to the next form
(check6 (rest list))) ; infinite loop
如果你想使用if
特殊运算符,你应该记住它有两种情况,当条件为真时和错误时,应该以这种方式嵌套表单(再次使用正确对齐):
(defun check6 (list)
(if (null list)
t
(if (not (numberp (first list)))
nil
(check6 (rest list)))))
但Common Lisp具有更方便的连接条件语法,cond
:
(defun check6 (list)
(cond ((null list) t)
((not (numberp (first list))) nil)
(t (check6 (rest list)))))
最后,请注意,通过使用迭代,还有其他方法可以解决您的问题:
(defun check6 (list)
(loop for element in list always (numberp element)))
或使用高级功能,以更简洁的方式:
(defun check6 (list)
(every #'numberp list))
答案 1 :(得分:0)
你一定要仔细看看Renzo编写函数的不同方法,但是你的代码可以通过早期从函数返回来修补:
(defun check6 (list)
(if (null list) (return-from check6 'TRUE))
(if (not (numberp(first list))) (return-from check6 nil))
(check6 (rest list)))
答案 2 :(得分:0)
你得到一个堆栈溢出,因为该函数永远不会终止。
Lisp中函数的结果是函数体中最后一个表达式的值
在你的情况下是(check6 (rest list))
。
我怀疑你正在考虑其他一些语言,这可能是用(用一种完全虚构的语言)写的:
bool check6(List list)
{
if (list.empty())
return true;
if (!isNumber(list.head()))
return false;
return check6(list.tail());
}
但你的条件不会从函数返回结果;他们的结果只是因为你没有对它们做任何事情而被丢弃。
在上面的虚构语言中,您的功能将是
bool check6(List list)
{
if (list.empty())
true;
if (!isNumber(list.head()))
false;
return check6(list.tail());
}
你可能会看到出了什么问题。
我个人发现与逻辑表达相比,难以遵循多管齐下的条件。
如果你写下列表是所有数字的条件:
直接翻译成Lisp:
(defun check6 (list)
(or (null list)
(and (numberp (first list))
(check6 (rest list)))))
用虚构的语言,
bool check6(List list)
{
return list.empty() || (isNumber(list.head()) && check6(list.tail()));
}
但是一旦你熟悉了高阶函数,你可能会写
(defun check6 (list)
(every #'numberp list))
这可能是Lisp-y最多的解决方案。