On Wed, Aug 5, 2009 at 08:05, 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:
> user=> (partition-with odd? [3 4 8 7 9 2 4 6])
> [[] [4 8] [] [2 4 6]]
> (The empty collections are from before 3 and between 7 and 9, from the look
> of it.
> user=> (remove empty? (partition-with odd? [3 4 8 7 9 2 4 6]))
> ([4 8] [2 4 6])
> gives what you might want instead, in some situations.)
>
> 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.
> Further experimentation shows that there isn't even a type-safety reason to
> prefer merge. 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...

At first, I figured it'd be

(defn merge
  "Returns a map that consists of the rest of the maps conj-ed onto
  the first.  If a key occurs in more than one map, the mapping from
  the latter (left-to-right) will be the mapping in the result."
  [& maps]
  (when (some identity maps)
    (reduce #(conj (or %1 {}) %2) maps)))

Merge combines (by reducing with conj) the maps its given. The
difference is in how nil as the first argument is handled. When the
first argument is nil, it is treated as if it were an empty map.

(clojure has a somewhat ambiguous relation to nil. Often nil is
treated as an empty collection, in this case en empty map. In contrast
to regular empty collections, however, nil is considered false when
evaluated as a boolean.)

user> (merge {} {1 1.0} {2 2.0 3 3.0})
{3 3.0, 2 2.0, 1 1.0}

user> (merge nil {1 1.0} {2 2.0 3 3.0})
{3 3.0, 2 2.0, 1 1.0}

The other differences stem from the fact that conj works a little
differently with maps than it does with lists and the fact that conj
considers nil equivalent to empty list (unlike merge, which considers
it equivalent to empty map).

user> (conj nil {1 1.0} {2 2.0 3 3.0})
({2 2.0, 3 3.0} {1 1.0})
user> (conj {} {1 1.0} {2 2.0 3 3.0})
{3 3.0, 2 2.0, 1 1.0}

Here we also notice that conj supports more than two arguments, which
makes me wonder why merge uses reduce in the first place. It would
seem to be unnecessary.

(defn my-merge [& maps]           ;; this appears equivalent to
clojure.core/merge
    (when (some identity maps)
        (apply conj (cons (or (first maps) {}) (rest maps)))))

// ben

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