2011-09-20 17 views
32

Common Lisp有return-from;在Clojure中是否有任何種類的return,當你想從一個函數提前返回時?如何在Clojure早期從函數返回?

+5

Clojure的代碼往往不被構建爲一系列的語句,因此返回早期不一定有意義。如果你想舉一個你想要的地方的例子,人們可能會提出替代方案。 – Chuck

回答

20

clojure中沒有任何顯式的return語句。你可以使用一個catch /拋出結合在了一起下鍋的東西,如果你想要,但由於Clojure是遠遠超過Common Lisp的更多的功能,很有可能你居然需要早日迴歸權在一些嵌套塊的中間比小得多CL。我可以看到返回語句的唯一「好」理由是當你在clojure中以非慣用方式處理可變對象時。

我不會走得太遠,因爲說這是永遠不會有用的,但我認爲在Clojure中,如果您的算法需要一個return語句,這是一個重大的代碼味道。

+3

感謝您的提示。作爲一個具體的例子:當解析命令行參數時,我想檢查每個選項是否有效。起初,我嘗試檢查每個選項,如果一個選項無效,那麼我想在繼續驗證其餘選項之前向用戶返回一條有用的消息。在實現函數中間返回是一種代碼異味之後,我寫了一個「validate」函數,它返回一個消息列表(每個無效選項值一個消息)。如果validate返回的消息列表爲空,則所有選項都會成功驗證。重構之後更好! – Upgradingdave

0

總之,沒有。如果這是一個真正的問題給你,那麼你可以避開它 「the maybe monad」單子有高智力開銷所以很多情況下clojurians傾向於避免編程「如果失敗,返回」風格。

它有助於打破功能成更小的函數來從此減少摩擦。

13

我在Clojure中沒有專家,但似乎沒有這些結構來嘗試更多的功能。看看什麼斯圖爾特哈洛韋說here

的Common Lisp還支持一回,從宏觀到從 中間功能的「迴歸」。這鼓勵了編程的迫切風格,Clojure不鼓勵。

但是,您可以用不同的方式解決相同的問題。這裏是 所述返回來自實施例,在功能樣式重寫,使得沒有 返回從需要:

(defn pair-with-product-greater-than [n] 
(take 1 (for [i (range 10) j (range 10) :when (> (* i j) n)] [i j]))) 

即,使用延遲序列和根據條件返回值。

17

除非你正在編寫一些非常時髦的代碼,你會永遠想提前返回的唯一原因是,如果某些條件得到滿足。但是因爲函數總是返回最後一個表單的計算結果,所以if已經是這個函數了 - 只要把你想返回的值放在if的主體中,並且如果滿足條件就會返回該值。

0

已經給出的if選項可能是最好的選擇,並注意因爲地圖是容易的,你總是可以在有效的狀態下返回的錯誤條件{:error "blah"}{result: x}

0

在Clojure中沒有返回語句。即使您選擇不使用流程結構(如ifwhen)執行某些代碼,該函數也會始終返回某些內容,在這些情況下爲nil。唯一的出路是拋出一個異常,但即使如此,它也會一直冒泡並殺死你的線程,或者被一個函數捕獲 - 這將返回一個值。

19

當你需要早日退出計算,你需要一種方法來做到這一點,而不是純粹主義者的爭論。通常,當你減少一個大集合時需要它,並且某個值表示在進一步處理集合時沒有意義。爲此,實用的Clojure提供了reduced函數。

一個簡單的例子可以說明,當乘以一個數字序列時,如果遇到一個零,那麼您已經知道最終結果將爲零,因此您不需要查看剩餘的序列。這裏是你如何代碼與reduced

(defn product [nums] 
    (reduce #(if (zero? %2) 
       (reduced 0.0) 
       (* %1 %2)) 
      1.0 
      nums)) 

reduced包你給它一個定點的數據結構,使reduce知道停止從收集閱讀,只是現在返回reduced值的值。嘿,它是純粹的功能,甚至!

你可以看到發生了什麼事情,如果你有包裹上述ifdo一個(println %1 %2)

user=> (product [21.0 22.0 0.0 23.0 24.0 25.0 26.0]) 
1.0 21.0 
21.0 22.0 
462.0 0.0 
0.0 

user=> (product [21.0 22.0 23.0 24.0 25.0 26.0]) 
1.0 21.0 
21.0 22.0 
462.0 23.0 
10626.0 24.0 
255024.0 25.0 
6375600.0 26.0 
1.657656E8 
+5

這應該是正確的答案。 「當你需要早日退出計算機時,你需要一種方法來做到這一點,而不是純粹主義者的爭論。」效率永遠是必須的。期。函數檢查一個id是否在一組映射中被複制的例子:(defn duplicated?[id myset](reduce(fn [av](if(=(:id v)id)(reduced true)false))假myset)) – Chocksmith