Mars
Mars

Reputation: 8854

Non-map collection predicate?

Is there a Clojure predicate that means "collection, but not a map"?

Such a predicate is/would be valuable because there are many operations that can be performed on all collections except maps. For example (apply + ...) or (reduce + ...) can be used with vectors, lists, lazy sequences, and sets, but not maps, since the elements of a map in such a context end up as clojure.lang.MapEntrys. It's sets and maps that cause the problem with those predicates that I know of:

Of course I can define such a predicate, e.g. like this:

(defn coll-but-not-map?
  [xs]
  (and (coll? xs) 
       (not (map? xs))))

or like this:

(defn sequential-or-set?
  [xs]
  (or (sequential? xs)
      (set? xs)))

I'm wondering whether there's a built-in clojure.core (or contributed library) predicate that does the same thing.

This question is related to this one and this one but isn't answered by their answers. (If my question is a duplicate of one I haven't found, I'm happy to have it marked as such.)

Upvotes: 5

Views: 330

Answers (2)

fl00r
fl00r

Reputation: 83680

For example (apply + ...) or (reduce + ...) can be used with vectors, lists, lazy sequences, and sets, but not maps

This is nothing about collections, I think. In your case, you have a problem not with general apply or reduce application, but with particular + function. (apply + [:a :b :c]) won't work either even though we are using a vector here.

My point is that you are trying to solve very domain specific problem, that's why there is no generic solution in Clojure itself. So use any proper predicate you can think of.

Upvotes: 3

Josh
Josh

Reputation: 4806

There's nothing that I've found or used that fits this description. I think your own predicate function is clear, simple, and easy to include in your code if you find it useful.

Maybe you are writing code that has to be very generic, but it's usually the case that a function both accepts and returns a consistent type of data. There are cases where this is not true, but it's usually the case that if a function can be the jack of all trades, it's doing too much.

Using your example -- it makes sense to add a vector of numbers, a list of numbers, or a set of numbers. But a map of numbers? It doesn't make sense, unless maybe it's the values contained in the map, and in this case, it's not reasonable for a single piece of code to be expected to handle adding both sequential data and associative data. The function should be handed something it expects, and it should return something consistent. This kind of reminds me of Stuart Sierra's blog post discussing consistency in this regard. Without more information I'm only guessing as to your use case, but it's something to consider.

Upvotes: 2

Related Questions