为什么默认不when-let
支持多个绑定?if-let
所以:
(when-let [a ...
b ...]
(+ a b))
...代替:
(when-let [a ...
(when-let [b ...
(+ a b)))
我知道我可以编写自己的宏或使用 monad(如此处所述:http: //inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html)。
为什么默认不when-let
支持多个绑定?if-let
所以:
(when-let [a ...
b ...]
(+ a b))
...代替:
(when-let [a ...
(when-let [b ...
(+ a b)))
我知道我可以编写自己的宏或使用 monad(如此处所述:http: //inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html)。
因为(if-let
至少)对于“其他”情况如何处理并不明显。
至少,出于更好的方式在 clojure 中嵌套 if-let 的动机,我开始编写一个宏来执行此操作。给定
(if-let* [a ...
b ...]
action
other)
它会产生
(if-let [a ...]
(if-let [b ...]
action
?))
我不清楚如何继续(“其他”有两个地方)。
你可以说任何失败都应该有一个替代方案,或者没有一个替代方案when-let
,但如果任何测试改变状态,那么事情仍然会变得一团糟。
简而言之,它比我预期的要复杂一些,所以我想当前的方法避免了对解决方案的要求。
另一种说法是:你假设if-let
应该像let
. 更好的模型可能是cond
,它不是“嵌套 if”,而是更多“替代 if”,因此不适合范围......或者,另一种说法:if
不处理这种情况好点。
这是当-让*:
(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)) ~@body))
`(do ~@body)))
用法:
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
这是 if-let*:
(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
编辑:原来绑定不应该以 else 形式泄露。
如果您使用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 在遇到 nil 值时会短路。
(来自第 6.5.1 节无)