我希望在Lisp中实现一个基本条件的递归函数,但是由于Lisp中没有返回语句,我无法做到这一点。
我的Lisp代码是基于这个C代码编写的。
if (n==0) return;
我该如何在Lisp中实现这个功能?
我希望在Lisp中实现一个基本条件的递归函数,但是由于Lisp中没有返回语句,我无法做到这一点。
我的Lisp代码是基于这个C代码编写的。
if (n==0) return;
Common Lisp 有一个特殊形式叫做 RETURN-FROM (以及它的相关形式 RETURN),用于实现你想要的功能。
(defun accumulate-list (list)
(when (null list)
(return-from accumulate-list 0))
(+ (first list)
(accumulate-list (rest list))))
话虽如此,我更喜欢在编写递归函数时使用COND。
(defun accumulate-list (list)
(cond
((null list)
0)
(t
(+ (first list)
(accumulate-list (rest list))))))
cond
中的一个子句没有主体形式,则如果测试表达式返回非nil值,则返回测试表达式的结果。这意味着您可以编写(cond ((null list) 0) ((+ (first list) ...)))
;在这种情况下不需要t
。 - Joshua Taylorelse
而不是将表达式用作测试形式,因为else
表达式处于尾部位置,而测试形式仍然必须经过真实性测试。 - C. K. Youngdefun
,所以我假设是Common Lisp。如果有后续子句,我可以理解为什么独立测试会处于非尾位置,但如果它是最后一个子句,那么独立测试不就处于尾位置了吗?例如,在(cond ... ((+ 2 3)))
中,如果你一直到达(+ 2 3)
,那么它将成为返回值。这就像(and ... last)
和(or ... last)
的情况,不是吗? - Joshua Taylor#f
(在标准术语中是唯一的false值)和“未指定的值”之间存在差异(如果cond
“掉落”最后一个子句,则返回该值,并且通常为实现提供的(void)
)。因此,在Scheme中,仅用于测试的最后一个子句不能简单地优化为else
。(但我可以看到您如何在CL中执行此操作,因为nil
既是false值,也是如果执行掉落,则是cond
的结果)。 - C. K. Young(<test> <expression> ...)
,所以(正如你过去提醒我的那样 ;)),可以有 零 个表达式。之后,它说,“如果所选子句仅包含测试而没有表达式,则测试的值将作为结果返回。” 因此 Scheme 确实 支持 (cond ... (test))
求值为 test
求值的任何内容。(它是否处于尾位置仍然未知。) - Joshua Taylor对于 Algol 程序员(或其许多方言,如 C、Java、Perl 等),LISP 中的每个表达式都像是一个“返回表达式”。例如:
{
int x = 10;
if( x == 10 )
return 10 * 5;
else
return 5 * 19;
}
;; direct version
(let ((x 10))
(if (= x 10)
(* 10 x)
(* 5 x)))
;; if can be anywhere
(let ((x 10))
(* x
(if (= x 10)
10
5))))
if
更像是三元运算符 ( expression ? consequent : alternative )
而不是 C 的 if
。return
的示例要翻译,我看到您并没有使用 return
返回一个值,而是将其作为 goto
早期退出函数。由于 goto 仍然被认为是有害的,即使 CL 的 return-from
肯定是最好的直译,但它并不总是正确的答案。nil
。(if (zerop x)
nil
(something-else x))
如果您需要多个语句(用于副作用),则使用let
,progn
或将整个内容切换为cond
:
;; 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*))))
return-from
是没有问题的。 :) - Will Nesscall/cc
,我几乎从不使用它。 - SylwesterconcatMap ... span ...
范例)。对我来说,与标志打交道似乎更加混乱。 - Will Nessif
语句放在整个代码块前面,并在需要返回“nothing”时使用nil
而不是return
。(defun somefunc (n)
(if (zerop n)
0
(+ n (somefunc (- n 1)))))
n==0
,递归函数返回 0。否则,它执行加法,将 n
加到 f(n-1)
上,并返回该结果。(请注意,这不是理想的算法,只是一个递归函数的示例)。n==0
,则上述代码返回 0。如果 n>0
,它将返回 +
表达式的结果。cond
就是方法(如前所述)。无论哪种方式,最后一个执行的东西的值都是函数的值。
(when (= n 0) (return-from foo nil))
在上面的 when 表单中,nil 可以被更复杂的表单替换,但如果需要,您可能希望构建(cond)
或(case)
等的实现。 - miercoledi