Lisp中是否有类似于C的return语句?
我想在用Lisp编写的递归函数中实现一个基本条件,但我不能这样做,因为Lisp中没有return语句 我的Lisp代码基于此C代码Lisp中是否有类似于C的return语句?,lisp,Lisp,我想在用Lisp编写的递归函数中实现一个基本条件,但我不能这样做,因为Lisp中没有return语句 我的Lisp代码基于此C代码 if (n==0) return; 如何在Lisp中实现这一点?对于一个Algol程序员(或它的许多方言之一,如C、Java、perl等)Lisp中的每个表达式都像“返回表达式”一样工作。例如: { int x=10; 如果(x==10) 返回10*5; 其他的 返回5*19; } 在LISP中,可以这样编写: ;;直接版本 (让((x 10)) (如果(=x1
if (n==0) return;
如何在Lisp中实现这一点?对于一个Algol程序员(或它的许多方言之一,如C、Java、perl等)Lisp中的每个表达式都像“返回表达式”一样工作。例如:
{
int x=10;
如果(x==10)
返回10*5;
其他的
返回5*19;
}
在LISP中,可以这样编写:
;;直接版本
(让((x 10))
(如果(=x10)
(*10倍)
(*5 x)))
;; 如果你能在任何地方
(让((x 10))
(*x
(如果(=x10)
10
5))))
正如您可能注意到的那样,LISPif
更像三元运算符(表达式?结果:可选)
,而不是Cif
编辑
现在,您已经在C中添加了一个示例usngreturn
,希望对其进行翻译,我发现您并没有使用return
返回值,而是使用goto
提前退出函数。因为goto仅仅使用CL从
返回并不总是正确的答案,即使这肯定是最好的直译
在任何LISP中,您都需要提供一个返回值,即使您不打算使用它(对于因其副作用而调用的函数)。如果不打算使用该值,可以使用nil
:
(if (zerop x)
nil
(something-else x))
如果您需要多个语句(用于副作用),请使用let
、progn
或将整个语句切换到状态:
;; using let to bind as well as implicit progn
(if (zerop x)
nil
(let ((tmp (gethash x *h*)))
(setf (gethash x *h*) (+ x 1))
(something-else tmp)))
;; using progn
(if (zerop x)
nil
(progn
(setf (gethash x *h*) (+ (gethash x *h*) 1))
(something-else (gethash x *h*))))
;; using cond
(cond ((zerop x) nil)
(t
(setf (gethash x *h*) (+ (gethash x *h*) 1))
(something-else (gethash x *h*))))
CommonLisp有一种特殊的形式(和它的相对形式)来做你想做的事情
(defun accumulate-list (list)
(when (null list)
(return-from accumulate-list 0))
(+ (first list)
(accumulate-list (rest list))))
话虽如此,我还是喜欢在编写递归函数时使用
(defun accumulate-list (list)
(cond
((null list)
0)
(t
(+ (first list)
(accumulate-list (rest list))))))
您只需将if
设置为整个身体,如果您确实希望返回值返回“nothing”,则将设置为nil
而不是return
因此,要将0到n之间的所有数字相加:
(defun somefunc (n)
(if (zerop n)
0
(+ n (somefunc (- n 1)))))
因此,如果n==0
,则递归函数返回0。否则它执行加法,将n
添加到f(n-1)
并返回该结果。(请注意,这不是理想的算法,只是递归函数的一个示例)
请记住,Lisp将函数中最后执行的expr的值作为其值返回。如果n==0
,则上面的返回值为0。如果n>0
,则返回+
表达式的结果
如果您需要一个多步骤测试(例如确保您没有通过负数),cond
是一种方法(如前所述)。无论哪种方式,最后执行的内容的值就是函数的值。注意,如果cond
中的子句没有主体形式,那么如果测试形式返回非nil,则返回测试形式的结果。这意味着您可以编写(cond((null list)0)((+(first list)…)
;在这种情况下,不需要使用t
。@JoshuaTaylor(我的评论不适用于CL。)在Scheme中,最好使用else
而不是使用表达式作为测试表单,因为else
表达式处于尾部位置,而测试表单仍然需要测试真实性。@JoshuaTaylor谢谢。我不知道。@ChrisJester-Young关于Scheme/CL差异的观点很好;这个问题只是标记了一下,所以不清楚目标Lisp是什么,但是这个答案使用了defun
,所以我假设是Common Lisp。我可以理解,如果有以下条款,为什么独立测试会处于非尾部位置,但如果是最后一个条款,独立测试不会处于尾部位置。例如,在(cond…(+23))
中,如果您一直到(+23)
,那么这将是返回值。这就像(and…last)
和(or…last)
的情况一样,不是吗?@ChrisJester-Young(不过,我意识到,这个方案有一个特定的尾部位置列表,所以这里可能没有涉及到这一点。)Lisp经常被用作函数式编程语言。这意味着term/stdout的输出被认为是“副作用”,并且有点不干净(没有那么严重的负面含义)。当然,Common Lisp中的任何函数的计算结果都会下降到其最终形式的值。因此,对于类似中止的情况,如果函数中的n等于0,我们将调用#'foo,您可能会使用条件函数-在大多数情况下,这可能是#'cond函数,但这里有一个简单的实现,使用#'when,一个经常内置的宏(when(=n0)(从foo nil返回))
在上面的when表单中,nil可以被更复杂的表单替换,但是如果有必要,您可能需要构造(cond)
或(case)
等的实现。@miercoledi lisp的功能并不比perl强,除了简单的引用。如果不引入一个状态机,一些问题就无法以函数式的方式解决,该状态机可以有效地执行与命令式代码相同的操作,但环境中的转换是在每次操作时通过复制完成的。其中一个问题是部分缩减,即您希望在转换环境时缩减步骤列表,但在满足特定条件时停止缩减;“命令式”代码有效地抽象了其复杂性,而“纯函数式”则使其不切实际。例如,纯函数式方法难以表达在我的数组xs中查找字符串“hi”的索引,因为reduce即使在找到它之后也必须遍历整个数组,过滤器将遍历整个数组,甚至不知道第一个是什么,因为它是一个无序操作。因此,如果不引入状态机,就无法正确表示此问题