On Friday, September 9, 2016 at 11:36:22 AM UTC-5, Alan Thompson wrote: > > Hi Colin, > > I too have been bitten by this type of inconsistency in clojure.core > functions. >
I disagree that the problem here is consistency. The core functions are very consistent, but I think it's easy to build an insufficiently detailed mental model of what should happen when you're not aware of the distinction between collection functions (take and return data structures - things like conj, merge, assoc, get) and sequence functions (take and return sequences or really seq-ables - map, filter, etc). > The root of the problem is that conj has different behavior for lists and > vectors, and that a seq behaves like a list. When map, filter, etc convert > the source vector into a seq, the behavior of conj changes accordingly. > In my opinion, the root of the problem is not being aware enough of when you move from working with data structures (like vectors) into working with sequence abstractions. Becoming more aware of the distinction and when those transitions occur is one of the more subtle aspects of learning Clojure. I wrote this not too long ago on a very similar question on reddit: https://www.reddit.com/r/Clojure/comments/4ve288/conj_i_just_dont_get_it_can_someone_help_me/ In order to avoid this kind of unpredictability, > Just to belabor it, everything here is totally predictable already. > you may wish to explore some of the functions to the Tupelo library. The > goal is to make things simpler, more obvious & predictable, and as > bulletproof as possible. One example is the append function. Here is a > sample program comparing conj and append: > > (ns clj.core > (:require [tupelo.core :as t] )) > (t/refer-tupelo) > > (def v [1 2 3]) > > (conj v 4) => [1 2 3 4] > (conj (map identity v) 4) => (4 1 2 3) > (conj (remove (constantly false) v) 4) => (4 1 2 3) > (conj (filter identity v) 4) => (4 1 2 3) > > As I wrote in the link above, I don't ever write code like this. When working with data in terms of seqs (map,remove,filter) you should be thinking in aggregates not in terms of individual values. Calling conj around a sequence is taking you from level of abstraction down into a lower level. This never comes up when I write Clojure (not exaggerating for effect, it just doesn't). I can't suggest an alternative here because the example is too narrow. Occasionally (much less now that we have transducers) I will have data in a seq and want to put it in a collection - into, vec, set are all sufficient to do so. Usually I find that either I can just leave it as a seq and continue OR that I can back up and make a collection instead of a seq in the first place (by using transducers, into, etc). > (t/append v 4) => [1 2 3 4] > (t/append (map identity v) 4) => [1 2 3 4] > (t/append (remove (constantly false) v) 4) => [1 2 3 4] > (t/append (filter identity v) 4) => [1 2 3 4] > > > I disagree with everything about this. :) In my opinion you are working against Clojure's strengths in going down this path. > I think simpler and more bulletproof functions can go a long toward making > Clojure easier to use, especially for beginners or when you are uncertain > about the exact type of a parameter. > I think more work on understanding the collection and sequence layers would pay far greater dividends than what you are suggesting. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.