2012-07-26 75 views

回答

13

因爲(爲if-let,至少)這不是什麼明顯與「其他」的情況下做的。

至少,通過Better way to nest if-let in clojure促使我開始寫一個宏這樣做。鑑於

(if-let* [a ... 
      b ...] 
    action 
    other) 

它會產生

(if-let [a ...] 
    (if-let [b ...] 
    action 
    ?)) 

,這是我不清楚如何繼續(有兩個地方爲「其他」)。

你可以說任何失敗都應該有一個替代方案,或者對於when-let應該有一個替代方案,但是如果任何測試變異狀態,那麼事情仍然會變得混亂。

總之,這是一個多一點比我預想的複雜,所以我想目前的做法避免了不得不做的解決方案應該是什麼樣的呼叫。

說同樣的事情的另一種方式:你假設if-let應嵌套像let。一個更好的模型可能是cond,這不是一個「嵌套是否」,而是更多的「另類如果」,所以不適合範圍嗯......或者,但稱它的另一種方式:if不處理這種情況下更好。

+0

'if-let *'宏也可以很好地回答我的問題;) – 2012-07-26 22:16:38

+0

但它不存在 - 我看不到處理「其他」部分的好方法。 – 2012-07-26 22:45:45

+1

啊 - 好點。當然讓*可能。 – 2012-07-27 08:37:52

4

如果使用cats,再有就是,你可能會發現有用的一個功能mlet

(use 'cats.builtin) 
(require '[cats.core :as m]) 
(require '[cats.monad.maybe :as maybe]) 

(m/mlet [x (maybe/just 42) 
     y nil] 
    (m/return (+ x y))) 
;; => nil 

正如你所看到的,遇到一個零值時MLET短路。

(從6.5節。1無)

6

這裏時,讓*:

(defmacro when-let* 
    "Multiple binding version of when-let" 
    [bindings & body] 
    (if (seq bindings) 
    `(when-let [~(first bindings) ~(second bindings)] 
     (when-let* ~(vec (drop 2 bindings)) [email protected])) 
    `(do [email protected]))) 

用法:

user=> (when-let* [a 1 b 2 c 3] 
       (println "yeah!") 
       a) 
;;=>yeah! 
;;=>1 


user=> (when-let* [a 1 b nil c 3] 
       (println "damn! b is nil") 
       a) 
;;=>nil 


下面是如果-讓*:

(defmacro if-let* 
    "Multiple binding version of if-let" 
    ([bindings then] 
    `(if-let* ~bindings ~then nil)) 
    ([bindings then else] 
    (if (seq bindings) 
    `(if-let [~(first bindings) ~(second bindings)] 
     (if-let* ~(vec (drop 2 bindings)) ~then ~else) 
     ~else) 
    then))) 

用法:

user=> (if-let* [a 1 
       b 2 
       c (+ a b)] 
       c 
       :some-val) 
;;=> 3 

user=> (if-let* [a 1 b "Damn!" c nil] 
       a 
       :some-val) 
;;=> :some-val 

編輯:原來綁定不應在其他形式被泄露。