Lisp 是一种表达式语言:它只有表达式而没有语句。这意味着对函数的调用的值只是该调用中涉及的最后一种形式的值 这与许多同时具有语句和表达式的语言不同,并且您必须使用显式 returns 显式地乱扔代码说一下函数调用的值是什么。
cond 形式又是一个表达式。像
这样的表达式的值
(cond
(<test1> <test1-form1> ... <test1-formn>)
(<test2> <test1-form1> ... <test1-formn>)
...
(<testn> <testn-form1> ... <testn-formnn>))
是第一个 <testm> 的 <testm-formn> 是真的,或者 nil 如果它们都不是(并且作为一种特殊情况,如果在测试后没有表单,那么值就是值那个测试)。
因此,在您的代码中,您只需要确保测试中成功的最后一个表单是您想要的值:
(defun positionRec (c l)
(cond
((atom l) nil)
((equal c (first l)) 1)
(t (+ 1 (positionRec c (rest l))))))
那么,return 有什么用?好吧,有时候你真的很想说‘好吧,在一些复杂的循环中,我已经完成了’:
(defun complicated-search (...)
(dolist (...)
(dolist (...)
(dotimes (...)
(when <found-the-interesting-thing>
(return-from complicated-search ...))))))
return 本身就等同于(return-from nil ...),并且各种结构将blocks 命名为nil 包裹在它们的身体周围。两个这样的,实际上是dotimes 和dolist,所以如果你想早点摆脱一个大循环,你可以这样做:
(defun complicated-search (...)
(dolist (...)
(when ...
(return 3)))) ;same as (return-from nil 3)
但总的来说,由于 Lisp 是一种表达式语言,因此您需要使用 return / return-from 的频率比使用其他一些语言要少得多。
在您的情况下,修改后的函数将失败:如果您遇到 ((atom l) nil) 情况,那么它将 nil 返回其父级,这将...尝试将 1 添加到其中。更好的方法是计算您的位置:
(defun position-of (c l)
(position-of-loop c l 1))
(defun position-of-loop (c l p)
(cond
((atom l) nil)
((equal c (first l)) p)
(t (position-of-loop c (rest l) (1+ p)))))
请注意,这(与您原来的一样)使用从 1 开始的索引:从零开始将与 CL 的其余部分更兼容。
将position-of-loop 设为本地函数可能是惯用的:
(defun position-of (c l)
(labels ((position-of-loop (lt p)
(cond
((atom lt) nil)
((equal c (first lt)) p)
(t (position-of-loop (rest lt) (1+ p))))))
(position-of-loop l 1)))
如果你想让它更简洁一点,你可以使用iteration macro:
(defun position-of (c l)
(iterate position-of-loop ((lt l) (p 1))
(cond
((atom lt) nil)
((equal c (first lt)) p)
(t (position-of-loop (rest lt) (1+ p))))))