Clojure中的条件绑定和执行

时间:2016-07-08 12:24:02

标签: clojure

我的Clojure代码中经常出现一个表单,我想知道是否有某种方法可以简化它。

这里是行为的描述"做操作X,如果操作的结果与谓词匹配,则将结果绑定到变量Y并执行一些代码。

这是我现在正在使用的实现:

(let [op-result (op ...)]
  (if-let [my-var (when (pred op-result) op-result)]
     then else))

对于我想要完成的事情,似乎太冗长了。有没有人有任何建议(除了编写我自己的宏)?

1 个答案:

答案 0 :(得分:0)

我猜你想在“then”分支中使用op-result。但是许多谓词函数返回true而不是它们的参数。所以你不能简单地写下这个:

(if-let [op-result (pred (op))]
  op-result ;maybe `true`, but you want `(op)`
  false)

您想要的核心表达是:

(and (pred x) x)

你可以写

(if-let [op-result (and (pred (op)) (op))]
  op-result
  false)

但如果(op)价格昂贵,那就更好了:

(if-let [op-result (let [x (op)] (and (pred x) x))]
  op-result
  false)

当然这有点乏味,所以如果你需要那么多,那么写一个宏可能是值得的。

我认为另一种方法是使谓词“真实”:

(defn truthy
  "Given a predicate function, return a new function.
  When the original predicate function returns true for some value,
  the new function returns the value (instead of true). Else returns
  false."
  [pred]
  (fn [v]
    (and (pred v) v)))

((truthy even?) 2) ; 2
((truthy even?) 3) ; false

(if-let [op-result ((truthy pred) (op))]
  op-result ;use op-result
  false)

同样,宏可能很方便。

在一些Lisps中,我使用模式匹配(在Racket中match,在Emacs Lisp中使用pcase。这些是cond之类的形式;通常,它们允许您在测试时应用谓词,同时绑定原始值。我不确定core.match是否可以执行此操作,或者,如果您只想将其包含在内,则可以执行此操作。

最后,我完全希望有人指出这样的事情已经作为Clojure中的单行而存在,我不知道。 :)但我想我会尝试一个答案,因为还没有其他人。