My apologies for misrepresenting Haskell's nubBy:

On 22 February 2010 19:15, Michał Marczyk <michal.marc...@gmail.com> wrote:
> The Haskell approach is to have two functions, nub and nubBy, which
> perform the task of distinct and the task of distinct with a
> user-provided keyfn, respectively.

Actually nubBy takes a binary function as its first argument and
performs equality comparisons of each successive element to each of
the elements collected into the result list using that function. A
corresponding Clojure function:

(defn distinct-by
  "A version following Haskell's nubBy."
  [f coll]
  (let [step (fn step [xs seen]
               (lazy-seq
                 ((fn [[x :as xs] seen]
                    (when-let [s (seq xs)]
                     (if (some #(f x %) seen)
                       (recur (rest s) seen)
                       (cons x (step (rest s) (conj seen x))))))
                  xs seen)))]
   (step coll #{})))

Here's one example of use:

user> (distinct-by #(= (class %1) (class %2)) [1 2 3 :a :b :c 'a 'b 'c])
(1 :a a)

And here's a Clojure version of the coolest Haskell one-liner I've ever seen:

user> (take 10 (distinct-by #(< 1 (gcd %1 %2)) (iterate inc 2)))
(2 3 5 7 11 13 17 19 23 29)

The alternative is to use a unary keyfn-based approach as I originally
suggested. This would work like so:

(defn distinct-by
  "NB. this isn't like Haskell's nubBy. f is supposed to be unary."
  [f coll]
  (let [step (fn step [xs seen]
               (lazy-seq
                 ((fn [[x :as xs] seen]
                    (when-let [s (seq xs)]
                      (if (some #(f x %) seen)
                        (recur (rest s) seen)
                        (cons x (step (rest s) (conj seen (f x)))))))
                  xs seen)))]
    (step coll #{})))

user> (distinct-by class [1 2 3 :a :b :c 'a 'b 'c])
(1 :a a)

Now I'm not really sure which one is more deserving of being called
distinct-by...

Sincerely,
Michał

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to