`everyp`/`somef` operational equality bug
Closed this issue · 5 comments
This line:
(every? #(and (p1 %) (p2 %) (p3 %)) args)
should be
(and (every? p1 args) (every? p2 args) (every? p3 args))
Basically the same problem as https://clojure.atlassian.net/browse/CLJ-2649 but in the rest arity.
You think it should check all of p1
before checking all of p2
, etc? My imperative intuition would loop over the arguments and check each predicate against them (as it works now).
Yes, I was surprised too. When I say "should", I'm referring to the operational equivalence with:
(defn everyp [& ps]
(fn [& args] (every? #(every? % args) ps)))
I think the "imperative" version you're talking about of would be:
(defn everyp [& ps]
(fn [& args] (every? (fn [x] (every? #(% x) ps) args)))
The problem is that the semantics are mixed. I think having both versions would be cool, but in different functions.
It's even worse than I thought. In these inner rest arities, ep3
checks x, y, z against p1, then p2 then p3, but then the every?
starts all over again for the rest of the args, but in the opposite order.
([x y z & args] (boolean (and (ep3 x y z)
(every? #(and (p1 %) (p2 %) (p3 %)) args))))))
ie., this is the checking order:
(p1 x) (p1 y) (p1 z)
(p2 x) (p2 y) (p2 z)
(p3 x) (p3 y) (p3 z)
(p1 args0)
(p2 args0)
(p3 args0)
(p1 args1)
(p2 args1)
(p3 args1)
...
I think it should be:
([x y z & args] (boolean (and (p1 x) (p1 y) (p1 z) (every? p1 args)
(p2 x) (p2 y) (p2 z) (every? p2 args)
(p3 x) (p3 y) (p3 z) (every? p3 args))))))
Smaller:
([x y z & args]
(let [test #(and (% x) (% y) (% z) (every? % args))]
(boolean (and (test p1) (test p2) (test p3)))))
Same problem with somef
. The arities that recur via sf2
, sf3
, sfn
flip the order.