Clojure:为什么if-let只允许绑定向量中有两种形式?
我什么时候用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 [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子句中使用绑定。更新了我的问题以澄清这一点。这绝对是有帮助的。谢谢但是,如果让我们一开始就不这样做,那为什么呢?