在clojure中嵌套if-let的更好方法

Mat*_*ard 10 if-statement clojure

说我有这张表格的地图:

(def m {:a "A" :b "B"})
Run Code Online (Sandbox Code Playgroud)

我想做一些事情,如果:a并且:b都不是零,我可以这样做:

(if-let [a (:a m)]
  (if-let [b (:b m)]
      ... etc ))
Run Code Online (Sandbox Code Playgroud)

要么

(if (and (:a m) (:b m))
  (let [{a :a b :b} m]
      ... etc ))
Run Code Online (Sandbox Code Playgroud)

甚至

(if (every? m [:a :b])
  (let [{a :a b :b} m]
      ... etc ))
Run Code Online (Sandbox Code Playgroud)

是否有更简洁(即一线)的方式来实现这一目标?

Ale*_*ard 7

我认为这里可能需要一个宏来创建你想要的行为.我从来没有写过(但是),但以下表示向我暗示这可能相当简单:

(let [{:keys [a b]} m]
   (when (every? identity [a b])
      (println (str "Processing " a " and " b))))
Run Code Online (Sandbox Code Playgroud)

使用:keys解构绑定的形式,every?并使键的向量的单个规范能够进行解构和检查,并且绑定的本地可用于以下代码块.

这可以用来制作一个宏,如 (when-every? [keys coll] code-with-bindings)

我可以用宏代码更新这个答案,如果我可以花时间来弄清楚如何做到这一点.


Mat*_*ick 6

你可以使用地图解构 - 一个Clojure的有用功能.这也利用了and短路的事实,并且在第二张地图中找不到的第一张地图中的任何键得到nil了一个假值:

(let [{a :a b :b} {:a 1 :b "blah"}] 
  (and a b (op a b)))
Run Code Online (Sandbox Code Playgroud)

好的,所以它是行而不是一行....这也不区分nil其他假值.