Hi, On Aug 5, 8:05 am, John Harrop <jharrop...@gmail.com> wrote: > I just saw someone post a bunch of Clojure code to comp.lang.lisp one > function from which was: > > (defn partition-with [pred coll] > (loop [in coll curr [] out []] > (if (empty? in) > (conj out curr) > (let [obj (first in)] > (if (pred obj) > (recur (rest in) [] (conj out curr)) > (recur (rest in) (conj curr obj) out)))))) > > This looks like it might be generally useful (and the CLL poster thought so > too); it splits a collection at items determined by the predicate, producing > a vector of vectors of items not matching the predicate.
You might want to rewrite that to return a lazy-seq, which just consumes just enough to provide the partition parts. (defn partition-with [pred coll] (letfn [(step [s] (lazy-seq (when-let [s (seq s)] (let [[fst rst] (split-with (complement pred) s)] (cons fst (step (rest rst)))))))] (step coll))) > The same CLL poster noticed that conj with two maps for arguments seems to > duplicate the functionality of merge. I've just tested this and it seems to > be true, even with key duplications: > > user=> (merge {:key2 2 :key3 3} {:key1 1 :key4 4 :key3 7} ) > {:key4 4, :key1 1, :key2 2, :key3 7} > user=> (conj {:key2 2 :key3 3} {:key1 1 :key4 4 :key3 7} ) > {:key4 4, :key1 1, :key2 2, :key3 7} > > This makes merge appear redundant. Looking at the source `merge` just reduces the maps using `conj`. `conj` on maps again, expect either a MapEntry or a vector. Otherwise it `seq`s its argument and `conj`s the elements onto the map. `seq`ing a map gives a seq of MapEntries, and hence we get the observed result. But the nil handling is different: user=> (conj nil {:a 5}) ({:a 5}) user=> (merge nil {:a 5}) {:a 5} Also there's merge-with. > Further experimentation shows that there isn't even a type-safety reason to > prefer merge. "type-safety" somehow seems funny in Clojure... Maybe "abstraction-safety"? > It doesn't throw on vectors. In fact: > > user=> (merge [1 2 3] 4) > [1 2 3 4] > user=> (merge '(1 2 3) 4) > (4 1 2 3) > user=> (merge #{1 2 3} 8) > #{1 2 3 8} > user=> (merge #{1 2 3} 3) > #{1 2 3} > user=> (merge #{1 2 3} #{4 3}) > #{1 2 3 #{3 4}} > user=> (conj #{1 2 3} #{4 3}) > #{1 2 3 #{3 4}} > > so merge appears to be strictly synonymous with conj. Curiouser and > curiouser... The contract (the docstring) says "maps". What happens when you feed different things to `merge` is unspecified. Since it uses internally `conj` it's no surprise, that it also works with vectors and sets. However you can see that the result are broken. There might be a hypothetical merge, which would also work on vectors and sets in a meaningful way: user=> (hypothetical-merge [1 2 3 4] [5 6]) [5 6 3 4] user=> (hypothetical-merge #{1 2} #{2 3}) #{1 2 3} For lists, however, I don't see such an operation. Upshot: `conj` and `merge` are not synonyms, cf. nil handling. Sincerely Meikel --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---