Clojure:为什么if-let只允许绑定向量中有两种形式?

Clojure:为什么if-let只允许绑定向量中有两种形式?,clojure,Clojure,我什么时候用if let喜欢 (if-let [a 2 b nil] (+ a b)) 我得到一个非法的辩论例外: clojure.core/if-let requires exactly 2 forms in binding vector... 类似的时候让 这不是我所期望的。If-let可以尝试所有绑定,在其中一个绑定失败时中断并计算else表达式 同样的投诉可在以下评论中找到:。我找到了一个并不令人满意的答案,因为海报在脑海中似乎有一个嵌套的if-let结构 限制*-let宏绑定的原因

我什么时候用if let喜欢

(if-let [a 2 b nil] (+ a b))
我得到一个非法的辩论例外:

clojure.core/if-let requires exactly 2 forms in binding vector...
类似的时候让

这不是我所期望的。If-let可以尝试所有绑定,在其中一个绑定失败时中断并计算else表达式

同样的投诉可在以下评论中找到:。我找到了一个并不令人满意的答案,因为海报在脑海中似乎有一个嵌套的if-let结构

限制*-let宏绑定的原因是什么

更新: 由于似乎不清楚,我对if let的期望是:

  • 它应该按顺序计算所有绑定
  • 当所有这些都成功时,它应该评估“then”案例
  • 如果一个绑定失败,它应该立即中断并评估“else”案例
  • 如果绑定失败,即使是成功的绑定,也不应在“else”表达式中可用

如果let
let
有不同的用途,并且如果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   
如果let旨在使绑定值时的操作更简单,只需测试和使用它。

请尝试以下方法:

(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"
试试这个

(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)))) (如果让 ([bindings-true-expr]`(如果let~bindings~true-expr-nil)) ([bindings true expr false expr] (续) (或(非(序列绑定))(非(零)(rem(计数绑定)2))) `(抛出(IllegalArgumentException.“如果let需要用户1中绑定向量中的2个或2个表单中的多个”)) (顺序(放下2个绑定)) `(如果让~(vec)(进行2次绑定)) (如果使用vec(丢弃2个绑定)) ~trueexpr ~false expr) ~false expr) :其他 `(如果let~(vec绑定) ~trueexpr ~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")) ) ) (如果允许,则测试DEFUT) (测试“if lets宏(正常情况)” (是(=0(如果让[x 0]x))) (是(=0(如果让[x0]x1))) (is(=1(如果let[x nil]x 1))) (是(=0(如果让[x0yx]y))) (是(=0(如果让[x0yx]y1))) (是(=1(如果让[x nil y x]y 1))) (是(=0(如果让[x0yxzy]z))) (是(=0(如果让[x0yxzy]z1))) (是(=1(如果让[x nil y x z y]y 1))) (是(=真(如果让[x真]真假))) (是(=假(如果让[x假]真假))) (是(=真(如果让[x真y真]真假))) (是(=假(如果让[x假y真]真假))) (是(=假(如果让[x真y假]真假))) (是(=真(如果让[x真y真z真]真假))) (是(=假(如果让[x假y真z真]真假))) (是(=假(如果让[x真y假z真]真假))) (是(=假(如果让[x真y真z假]真假))) ) ) (如果允许,则进行DEFUT测试) (测试“如果出现异常情况” (是(=(try(如果let[]true false)(捕获异常e(.getMessage e))) “如果let需要用户中绑定向量中的2个或2个表单中的多个:1”)) (是(=(try(如果让[x]为true-false)(捕获异常e(.getMessage e))) “如果let需要用户中绑定向量中的2个或2个表单中的多个:1”)) (是(=(try(如果让[x真y]真假)(捕获异常e(.getMessage e))) “如果let需要用户中绑定向量中的2个或2个表单中的多个:1”)) ) )
现在还不清楚你的if-let应该做什么。如果在let条款中第一次输入错误时失败?或者它应该只测试第一个条目,如果这是真的,则评估其他let子句,以便在下面的代码中使用?i、 e.将其视为嵌套函数:(if let[a2](let[b nil](+a b)))-我过去当然也希望使用该构造…@Korny:关于我的期望,请参阅我更新的问题。我不同意:您不应该使用
if let
如果您在
子句中要做的就是返回受测试约束的值。i、 e,与
(如果让[ans(+1 2 3)]ans:foo相比,
显然更适合编写
(或(+1 2 3):foo)
如果let
对测试某些东西并进一步操作它很有用。@amalloy也许我可以更清楚地说明这一点,您提到的代码描述了如果let和let不同的一种方式。最后一行描述了if-let的一个潜在用途。我将把return这个词改为use,也许这会澄清。@Arthurlfeldt:我不想在else子句中使用绑定。更新了我的问题以澄清这一点。这绝对是有帮助的。谢谢但是,如果让我们一开始就不这样做,那为什么呢?