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
-~----------~----~----~----~------~----~------~--~---

Reply via email to