我的Clojure代码中经常出现一个表单,我想知道是否有某种方法可以简化它。
这里是行为的描述"做操作X,如果操作的结果与谓词匹配,则将结果绑定到变量Y并执行一些代码。
这是我现在正在使用的实现:
(let [op-result (op ...)]
(if-let [my-var (when (pred op-result) op-result)]
then else))
对于我想要完成的事情,似乎太冗长了。有没有人有任何建议(除了编写我自己的宏)?
答案 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中的单行而存在,我不知道。 :)但我想我会尝试一个答案,因为还没有其他人。