我想在用Lisp編寫的遞歸函數中實現一個基本條件,但是我無法做到這一點,因爲在Lisp中沒有返回語句。Lisp中有什麼類似於C的return語句嗎?
我的Lisp代碼就是基於這種C代碼
if (n==0) return;
如何在Lisp中實現這一點?
我想在用Lisp編寫的遞歸函數中實現一個基本條件,但是我無法做到這一點,因爲在Lisp中沒有返回語句。Lisp中有什麼類似於C的return語句嗎?
我的Lisp代碼就是基於這種C代碼
if (n==0) return;
如何在Lisp中實現這一點?
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'中的子句沒有主體形式,那麼如果測試表單返回非零,則返回測試表單的結果。這意味着你可以編寫'(cond((null list)0)((+(first list)...)))';在這種情況下不需要't'。 – 2014-10-10 01:15:35
@JoshuaTaylor(我的評論不適用於CL)。在Scheme中,使用'else'代替使用表達式作爲測試表單更好,因爲'else'表達式處於尾部位置,而測試表單仍然必須進行真實性測試。 – 2014-10-10 02:41:33
@JoshuaTaylor謝謝。我不知道。 – 2014-10-10 05:04:54
對於Algol程序員(或者C,Java,perl等許多方言中的一個)每個表達式在LISP中的工作方式類似於「返回表達式」。例如:
{
int x = 10;
if(x == 10)
return 10 * 5;
else
return 5 * 19;
}
在LISP這可以寫成這樣的:
;; 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))))
正如你可能已經注意到LISP if
更像是三元運算符(expression ? consequent : alternative)
比一個C if
。
編輯
現在您已經添加了一個例子USNG用C return
要翻譯我看到你沒有使用return
返回一個值,但作爲一個goto
提前退出功能。由於goto is still considered harmful只是使用CL return-from
並不總是正確的答案,即使這肯定是最好的直譯。
在任何LISP中,即使您不打算使用它(對於稱爲副作用的函數),您仍需要提供返回值。如果你不打算使用的值,你可以只使用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*))))
我最近在某處讀過那些被認爲有害的GOTO,當Dijkstra發表那篇文章是那種自由跳進和跳出代碼塊的類型(使得這些塊在概念上有多個進入點和退出點),事實上在那即使是子程序,在程序集編程時也被認爲是新穎*範例*(函數調用協議只是程序員要保留的約定)。所以有人認爲(我回過頭來看我們的問題),算法上使用'return-from'時沒有什麼問題。 :) – 2014-10-10 11:25:22
@WillNess我喜歡它的概念仍然被認爲是有害的,並且有例外。這樣你每次寫它時都會考慮它。這就像Scheme中的'call/cc',我幾乎從不使用它。 – Sylwester 2014-10-10 11:38:41
我個人喜歡結構化的本地化gotos。 YMMV,他們*說。 :)最近我用C編寫了一些循環,有兩個入口點,它們有時不得不執行一些內部初始化(在'concatMap ... span ...'範例之後,基本上是通過塊來處理,然後生成一個平坦的輸出) 。與*標誌* *似乎非常* messier *,對我來說。 – 2014-10-10 11:49:34
你只需要把if
是整個身體,並把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
,則返回+
expr的結果。
如果您需要多步測試(例如,以確保您沒有通過負數),cond
是(如前所述)。無論哪種方式,執行的最後一件事的價值是該函數的價值。
Lisp經常用作函數式編程語言。這意味着對term/stdout的輸出被認爲是「副作用」,並且在某種程度上(沒有那麼重的負面含義)_unclean_。當然,Common Lisp中的任何函數都會評估其最終形式的值。 – miercoledi 2014-10-10 02:48:54
因此,對於類似_abort的東西,如果函數中的n等於0_,我們將調用**#'foo **您可能會使用條件 - 在大多數情況下,這可能是**#'cond * *函數,但這裏是一個簡單的實現,使用**#',這是一個經常內置的宏。 '(when(= n 0)(return-from foo nil))'在上面的_when_表單中,_nil_可以被更復雜的形式所取代,但是如果這是必要的,你可能想要構造一個'(cond)'或'(case)'等等。 – miercoledi 2014-10-10 02:50:46