2016-12-27 56 views
1

假設有必要檢查參數是否通過給定謂詞集合的一個真值測試。謂詞集合的短路真值測試

codewise:

(fn [x] 
    (or (pred1 x) (pred2 x) (pred3 x) (pred4 x))) 

由於or的實施中,第一truthy值之後這個短路。如預期。

這又如何通過使用謂詞的集合被改寫:

[PRED1 PRED2 pred3 pred4]

一個時髦的辦法是:

(fn [x preds] 
    (some?         ;; nil->false 
    (some true? (map #(% x) preds)))) 

這也證明,這一個不短路。可能是由於Clojure對懶惰序列的分塊。

我們可以做得更好嗎?

回答

4

的Clojure有一個some-fn功能:

user> ((some-fn true? false? nil?) true) 
true 
user> ((some-fn false? nil?) true) 
false 

或您的情況:

user> (defn any-pred? [x preds] 
     ((apply some-fn preds) x)) 

另一種經典的方式是做遞歸:

user> (defn any-pred? [x preds] 
     (when-let [[pred & preds] (seq preds)] 
      (or (pred x) (any-pred? x preds)))) 

user> (any-pred? true [false?]) 
nil 
user> (any-pred? true [true?]) 
true 
user> (any-pred? true [false? true?]) 
true 
user> (any-pred? true [false? nil?]) 
nil 
user> (any-pred? true [false? nil? true?]) 
true 
+0

更好'比使用顯式的遞歸recur'。 – Thumbnail

0

當我需要短路時,我使用減少。

(defn any-valid? [w & pred-fn-coll] 
    (reduce (fn [v pf] 
     (if (pf w) 
      (reduced true) 
      v)) false pred-fn-coll)) 

(any-valid? 1 even? odd?) 
;=> true 
(any-valid? 1 even? even?) 
;=> false 
0

我認爲這是map這是在你的解決方案中進行分塊。

嘗試

(defn any-true? [preds] 
    (fn [x] 
    (loop [preds preds] 
     (and (seq preds) 
      (or ((first preds) x) 
       (recur (rest preds))))))) 

((any-true? [odd? even?]) 3) ;true 

((any-true? []) 3)    ;nil 

((any-true? [even?]) 3)   ;nil 

((any-true? [odd? #(/ % 0)]) 3) ;true 

最後一個例子表明,該評估是懶惰。

0

另外,

(defn somep? [x [p & ps :as preds]] 
    (if-not (empty? preds) 
    (or (p x) (somep? x ps)))) 

(defn somep? [x [p & ps :as preds]] 
    (if-not (empty? preds) 
    (let [res (p x)] 
     (if-not res 
     (recur x ps) 
     res)))) 
+1

你的第一個替代方案可能是(當(seq preds)(或(p x)(recur x ps))))'時。 – Thumbnail