If statement 如果让clojure进来,更好的筑巢方式

If statement 如果让clojure进来,更好的筑巢方式,if-statement,clojure,If Statement,Clojure,假设我有此表单的地图: (def m {:a "A" :b "B"}) 如果:a和:b都不是零,我想做点什么,我可以做: (if-let [a (:a m)] (if-let [b (:b m)] ... etc )) 或 甚至 (if (every? m [:a :b]) (let [{a :a b :b} m] ... etc )) 有没有更简洁(即一行)的方法来实现这一点?没有?是一个很好的快捷方式: user> (not-any? nil? [

假设我有此表单的地图:

(def m {:a "A" :b "B"})
如果
:a
:b
都不是零,我想做点什么,我可以做:

(if-let [a (:a m)]
  (if-let [b (:b m)]
      ... etc ))

甚至

(if (every? m [:a :b])
  (let [{a :a b :b} m]
      ... etc ))

有没有更简洁(即一行)的方法来实现这一点?

没有?
是一个很好的快捷方式:

user> (not-any? nil? [(m :a) (m :b)])
true
user> (not-any? nil? [(m :a) (m :b) (m :d)])
false
user> 
您可以使用——Clojure的一个有用特性。这还利用了
短路的事实,并且在第二个映射中未找到的第一个映射中的任何键都会得到
nil
,一个错误值:

(let [{a :a b :b} {:a 1 :b "blah"}] 
  (and a b (op a b)))

好的,这是两行而不是一行。。。。此外,这并不区分
nil
和其他错误值。

我不太确定如果键具有非nil值,或者是否希望返回非nil键或值,您要做什么。所以,我刚刚解决了返回非零密钥的问题

您可以使用以下步骤作为最终解决方案的中间步骤

我展示了我使用的所有步骤,不是为了学究,而是为了提供一个完整的答案。名称空间是
repl test
。它有一个与之关联的main

repl-test.core=> (def m {:a "A" :b "B" :c nil})
#'repl-test.core/m

repl-test.core=> (keys m)
(:a :c :b)
最后:

; Check key's value to determine what is filtered through.
repl-test.core=> (filter #(if-not (nil? (%1 m)) (%1 m)) (keys m) )
(:a :b)

我认为这里可能需要一个宏来创建您想要的行为。我从未写过一本(至今),但下面的陈述向我表明,这可能相当简单:

(let [{:keys [a b]} m]
   (when (every? identity [a b])
      (println (str "Processing " a " and " b))))
使用解构绑定的
:keys
形式和
every?
可以对密钥向量的单个规范进行解构和检查,并且绑定的局部变量在以下代码块中可用

这可用于生成宏,例如
(当每个?[keys coll]代码都带有绑定时)


如果我能花点时间找出如何做,我可能会用宏代码更新这个答案。

顺便说一句,我发现了一个难看的单行线,因为
返回其参数列表中的最后一项,如果它们都是真的:

(if-let [[a b] (and (:a m) (:b m) [(:a m)(:b m)])]
    (println "neither " a " nor " b " is falsey")
    (println "at least one of " a " or " b " is falsey"))

(每个?一些?…)
不是更好吗?这样你就可以避免双重否定不是吗?当发现一个问题时,可以停止检查,在许多情况下,时间会略有改善
(if-let [[a b] (and (:a m) (:b m) [(:a m)(:b m)])]
    (println "neither " a " nor " b " is falsey")
    (println "at least one of " a " or " b " is falsey"))