2012-07-26 78 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 

编辑:原来绑定不应在其他形式被泄露。