Hi J,
I don't think there is a specific function in Clojure equivalent to
*pairwise?* but I it might be more idiomatic to use the functions available
in clojure.core to manipulate collections.
I would implement *pairwise?* in the following way, others might suggest
better/simpler ways though:
(defn pairwise?
[pred coll]
(->> coll
(partition 2 1)
(every? (partial apply pred))))
*partition* return a lazy sequence and *every?* stops consuming on the
first *false* result, so this actually only process as many pairs as
necessary.
Hope it helps,
Juan Facorro
On Monday, September 21, 2015 at 5:08:36 PM UTC-3, [email protected] wrote:
>
> Hey all --
>
> I recently found myself needing to check for pairwise property consistency
> across a sequence of elements, similar in spirit to inequality checking (in
> this case, date comparisons using clj-time *t/before?*). What I wanted
> was to do something like:
>
> (if (t/before? date-a date-b date-c date-d)
>
> ; elided
> )
>
>
> ...which is symmetric to the idiomatic usage of the inequality functions
> in clojure core (*=*, *>* and friends). Unfortunately, *t/before?* does
> not support variadic invocation, and after reading the source behind each
> of those functions, I discovered that they implement their own variadic
> overloads ad hoc, and there doesn't appear to be (at least I haven't yet
> discovered) a way to generalize pairwise property assertion over an
> arbitrarily large sequence of things.
>
> I would previously have solved this like:
>
> (reduce (fn [_ [x y]]
> (if (t/before? x y)
> true
> (reduced false))) true
> (partition 2 1 [(t/local-date 2015 1 1) (t/local-date 2015 2 1)
> (t/local-date 2015 3 1)]))
>
> ;-> true
>
>
> ...or even...
>
> (every? (fn [[x y]] (t/before? x y)) (partition 2 1 [(t/local-date 2015 1 1)
> (t/local-date 2015 2 1) (t/local-date 2015 3 1)]))
>
>
> ...which is sort of cumbersome and occludes my intent. I ended up writing
> a function to address this problem generally, and thought it might be
> useful to others (and possibly worth including in clojure). Here it is:
>
> (defn pairwise?
> "Returns true if every sequential pair satisfies pred; false otherwise."
> {:inline (fn [pred x y] `(~pred ~x ~y))
> :inline-arities #{3}}
> ([_ _] true)
> ([pred x y] (pred x y))
> ([pred x y & more]
> (if (pairwise? pred x y)
> (if (next more)
> (recur pred y (first more) (next more))
> (pairwise? pred y (first more)))
> false)))
>
>
> ...and the test cases:
>
> (deftest pairwise?
> (testing "Idiomatic cases"
> (is (pairwise? > 3 2 1 0))
> (is (pairwise? t/after? (t/local-date 2015 3 1) (t/local-date 2015 2 1)
> (t/local-date 2015 1 1)))
> (is (pairwise? #(= %1 (* -1 %2)) -1 1 -1 1))
> (is (not (pairwise? = 1 1 1 2 1))))
> (testing "Short circuits on false"
> (is (not (apply pairwise? = (concat [2 2] (repeat 1)))))))
>
>
> It accepts as its first argument any binary predicate, and applies it to a
> splat until the predicate returns false. The keen eye will notice it looks
> very similar to the variadic overload of *>*, which is what I used for
> reference. This means you can now do things like:
>
> (pairwise? t/before? (t/local-date 2015 1 1) (t/local-date 2015 2 1)
> (t/local-date 2015 3 1))
>
> ;-> true
>
>
> ...even though *t/after?* only supports a dyadic form. This also works
> nicely with apply to run against seqs:
>
> (apply pairwise? t/before? [(t/local-date 2015 1 1) (t/local-date 2015 2 1)
> (t/local-date 2015 3 1)])
>
> ;-> true
>
>
> Or, for properties that aren't necessarily correlated to ordering:
>
> (pairwise? #(= %1 (* -1 %2)) -1 1 -1 1)
>
> ;-> true
>
>
> Which of course works for the inequality operators (although they
> obviously support this natively):
>
> (pairwise? > 3 2 1 0)
>
> ;-> true
>
>
> As i said, I was unable to find anything in clojure core similar to
> *pairwise?*, although admittedly I've only been using clojure in anger
> now for around 4 months, so if I'm overlooking an in-built capability,
> please set me straight.
>
> Thoughts/suggestions/amendments/corrections welcome and appreciated!
>
> Cheers,
> -J
>
>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.