Lisp中是否有类似于C的return语句?

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

我想在用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))
(如果(=x10)
(*10倍)
(*5 x)))
;; 如果你能在任何地方
(让((x 10))
(*x
(如果(=x10)
10
5))))
正如您可能注意到的那样,LISP
if
更像三元运算符
(表达式?结果:可选)
,而不是C
if

编辑

现在,您已经在C中添加了一个示例usng
return
,希望对其进行翻译,我发现您并没有使用
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即使在找到它之后也必须遍历整个数组,过滤器将遍历整个数组,甚至不知道第一个是什么,因为它是一个无序操作。因此,如果不引入状态机,就无法正确表示此问题