当我使用if-let时
(if-let [a 2 b nil] (+ a b))
我收到IllegalArgumentException:
clojure.core/if-let requires exactly 2 forms in binding vector...
类似于when-let ...
这不是我所期望的。 If-let可以尝试所有绑定并在一个失败时中断并评估else表达式。
同样的投诉可以在clojuredocs的评论中找到。我发现答案here并没有真正满足,因为海报似乎有一个等效的嵌套if-let-structure。
有什么理由限制* -let宏的绑定?
更新: 由于似乎不清楚,我对if-let的期望是:
答案 0 :(得分:3)
if-let
和let
有不同的用途,if-let不仅仅是let的限制版本。实例if-let
与let
的不同之处在于,该值仅限于then子句,而不是else。
user> (if-let [ans (+ 1 2 3)] ans :foo)
6
user> (if-let [ans (+ 1 2 3)] ans ans)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ans in this context, compiling:(NO_SOURCE_PATH:1)
user> (let [ans (+ 1 2 3)] ans ans)
6
如果你想绑定一个值只是为了测试和使用它,if-let的目的是让生活更轻松。
答案 1 :(得分:3)
试试这个:
(defmacro if-let-multi
([bindings then-exp]
(let [values (take-nth 2 (rest bindings))]
`(if (and ~@values) (let ~bindings ~then-exp) false)))
([bindings then-exp else-exp]
(let [values (take-nth 2 (rest bindings))]
`(if (and ~@values) (let ~bindings ~then-exp) ~else-exp))))
这是在行动:
user> (if-let-multi [a 2 b nil] (+ a b))
false
user> (if-let-multi [a 2 b 3] (+ a b))
5
user> (if-let-multi [a 2 b nil] (+ a b) "NO WAY")
"NO WAY"
答案 2 :(得分:1)
试试这个。
(defmacro if-lets ([bindings true-expr] `(if-lets ~bindings ~true-expr nil)) ([bindings true-expr false-expr] (cond (or (not (seq bindings)) (not (zero? (rem (count bindings) 2)))) `(throw (IllegalArgumentException. "if-lets requires 2 or multiple of 2 forms in binding vector in user:1")) (seq (drop 2 bindings)) `(if-let ~(vec (take 2 bindings)) (if-lets ~(vec (drop 2 bindings)) ~true-expr ~false-expr) ~false-expr) :else `(if-let ~(vec bindings) ~true-expr ~false-expr))))
这个宏通过了以下测试。
(deftest ut-if-lets (testing "if-lets macro (normal cases)" (is (= 0 (if-lets [x 0] x))) (is (= 0 (if-lets [x 0] x 1))) (is (= 1 (if-lets [x nil] x 1))) (is (= 0 (if-lets [x 0 y x] y))) (is (= 0 (if-lets [x 0 y x] y 1))) (is (= 1 (if-lets [x nil y x] y 1))) (is (= 0 (if-lets [x 0 y x z y] z))) (is (= 0 (if-lets [x 0 y x z y] z 1))) (is (= 1 (if-lets [x nil y x z y] y 1))) (is (= true (if-lets [x true] true false))) (is (= false (if-lets [x false] true false))) (is (= true (if-lets [x true y true] true false))) (is (= false (if-lets [x false y true] true false))) (is (= false (if-lets [x true y false] true false))) (is (= true (if-lets [x true y true z true] true false))) (is (= false (if-lets [x false y true z true] true false))) (is (= false (if-lets [x true y false z true] true false))) (is (= false (if-lets [x true y true z false] true false))) ) ) (deftest ut-if-lets-ab (testing "if-lets macro (abnormal cases)" (is (= (try (if-lets [] true false) (catch Exception e (.getMessage e))) "if-lets requires 2 or multiple of 2 forms in binding vector in user:1")) (is (= (try (if-lets [x] true false) (catch Exception e (.getMessage e))) "if-lets requires 2 or multiple of 2 forms in binding vector in user:1")) (is (= (try (if-lets [x true y] true false) (catch Exception e (.getMessage e))) "if-lets requires 2 or multiple of 2 forms in binding vector in user:1")) ) )