> On 19 Jul 2018, at 21:17, Andy Fingerhut <andy.finger...@gmail.com> wrote: > > > If you wish for the Clojure core team to provide that style of documentation > for you, I expect your wish will not be fulfilled. It is not technically > difficult to replace all Clojure doc strings with more verbose variants. It > _is_ a lot of work to write documentation like that and maintain it over > time. For example, here is a whole bunch of stuff I wrote on the behavior of > clojure.core/= and clojure.core/hash. It took way more hours than I care to > admit: > https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/equality.md > > I believe someone wrote a book aiming to be a reference to all Clojure > functions, but don't recall the name or author at the moment, nor have I read > it.
Apologies for not resisting the plug: https://www.manning.com/books/clojure-standard-library It should be completed very soon. Also sympathetic with the complexities of equality: I still can't believe how much there is to say. Cheers Renzo > > Andy > > > > > On Thu, Jul 19, 2018 at 11:04 AM Benoît Fleury <m...@benfle.com> wrote: > I agree with Alex. It is important to understand the rationale behind the > behavior of conj. conj is for adding an element to a collection. It doesn't > say anything about ordering. It has been chosen as an operation, as > opposed to append/prepend, because it can be implemented with the > same time complexity for a lot of data structures. > > To convince myself that time complexity mattered in programming, I take > the example of a stack. If you give me an implementation of a stack that > push and pop items in linear time, I will write very inefficient programs > very quickly. To the point of not working at all. So it makes sense to me > that space/time complexity should be part of the signature of an operation. > > Now, I think the problem here comes from the fact that we have a tendency > to infer the semantic of an operation from its behavior on certain types. We > see that (conj [1 2] 3) returns [1 2 3] so we conclude that conj is for adding > an item at the end of a collection. And then we get surprised when the > behavior is "different" for other types. As Clojure programmers, it is > something > we need to be careful about and make sure we understand the actual > semantic of the operations. > > However, I think it is easier said than done. I would be ready to bet that a > lot of Clojure programs rely on the fact that conj *appends* to a vector or > *prepends* to a list. I agree that it is problematic. First, it makes the > understanding of the code harder because you need to remember the behavior > of conj on each type. And it prevents the implementation of conj to change > because so many programs rely on implementation details. But to all expert > Clojure programmers here, can you honestly think about what mental model you > use when using conj on vectors and lists? Are you really thinking: I'm adding > this element to this collection. I don't really care where it ends up :) ? > > So my questions are: > > 1. Am I wrong in thinking that most Clojure programmers use append/prepend > as mental models for the different implementations of conj? > > 2. Am I wrong in thinking that they shouldn't? > > 3. And if I'm not wrong, how could we make it easier for programmers to make > sure they code against the semantic of an operation and not its implementation > details? Is there methods, tools or tests that could help us with that? > > > On Thu, Jul 19, 2018 at 3:20 AM Didier <didi...@gmail.com> wrote: > Hey Alan, > > Nice job on Tupelo by the way. I do find it a bit bloated though, and that's > why I never use it. Any reason why all the different namespace are still > mixed together? Seem like they could each be an independent lib, like how the > datomic namespace was split out. > > On Wednesday, 18 July 2018 13:16:15 UTC-7, Alan Thompson wrote: > There is also a function `glue` for combining like collections: > > --------------------------------------------------------------------------------- > Gluing Together Like Collections > > The concat function can sometimes have rather surprising results: > > (concat {:a 1} {:b 2} {:c 3 > } ) > > ;=> ( [:a 1] [:b 2] [:c 3] ) > In this example, the user probably meant to merge the 3 maps into one. > Instead, the three maps were mysteriously converted into length-2 vectors, > which were then nested inside another sequence. > > The conj function can also surprise the user: > > (conj [1 2] [3 4 > ] ) > > ;=> [1 2 [3 4] ] > Here the user probably wanted to get [1 2 3 4] back, but instead got a nested > vector by mistake. > > Instead of having to wonder if the items to be combined will be merged, > nested, or converted into another data type, we provide the glue function to > always combine like collections together into a result collection of the same > type: > > ; Glue together like collections: > > ( > is (= (glue [ 1 2] '(3 4) [ 5 6] ) [ 1 2 3 4 5 6 ] )) ; all > sequential (vectors & lists) > > ( > is (= (glue {:a 1} {:b 2} {:c 3} ) {:a 1 :c 3 :b 2} )) ; all maps > > ( > is (= (glue #{1 2} #{3 4} #{6 5} ) #{ 1 2 6 5 3 4 } )) ; all sets > > ( > is (= (glue "I" " like " \a " nap!" ) "I like a nap!" )) ; all text > (strings & chars) > > > > ; If you want to convert to a sorted set or map, just put an empty one first: > > ( > is (= (glue (sorted-map) {:a 1} {:b 2} {:c 3}) {:a 1 :b 2 :c 3 > } )) > ( > is (= (glue (sorted-set) #{1 2} #{3 4} #{6 5}) #{ 1 2 3 4 5 6 } )) > An Exception will be thrown if the collections to be 'glued' are not all of > the same type. The allowable input types are: > > • all sequential: any mix of lists & vectors (vector result) > > • all maps (sorted or not) > > • all sets (sorted or not) > > • all text: any mix of strings & characters (string result) > > > > On Wed, Jul 18, 2018 at 1:13 PM, Alan Thompson <cloo...@gmail.com> wrote: > As someone mentioned, the functions `prepend` and `append` exist in the > Tupelo library to prevent this kind of confusion: > > from the README: > ------------------------------------------------------------------------------------ > Adding Values to the Beginning or End of a Sequence > > Clojure has the cons, conj, and concat functions, but it is not obvious how > they should be used to add a new value to the beginning of a vector or list: > > ; Add to the end > > > ( > concat [1 2] 3) ;=> IllegalArgumentException > > > ( > cons [1 2] 3) ;=> IllegalArgumentException > > > ( > conj [1 2] 3) ;=> [1 2 3] > > > ( > conj [1 2] 3 4) ;=> [1 2 3 4] > > > ( > conj '(1 2) 3) ;=> (3 1 2) ; oops > > > ( > conj '(1 2) 3 4) ;=> (4 3 1 2) ; oops > > > > ; Add to the beginning > > > ( > conj 1 [2 3] ) ;=> ClassCastException > > > ( > concat 1 [2 3] ) ;=> IllegalArgumentException > > > ( > cons 1 [2 3] ) ;=> (1 2 3) > > > ( > cons 1 2 [3 4] ) ;=> ArityException > > > ( > cons 1 '(2 3) ) ;=> (1 2 3) > > > ( > cons 1 2 '(3 4) ) ;=> ArityException > Do you know what conj does when you pass it nil instead of a sequence? It > silently replaces it with an empty list: (conj nil 5) ⇒ (5) This can cause > you to accumulate items in reverse order if you aren’t aware of the default > behavior: > > (-> nil > > ( > conj 1 > ) > ( > conj 2 > ) > ( > conj 3 > )) > > ;=> (3 2 1) > These failures are irritating and unproductive, and the error messages don’t > make it obvious what went wrong. Instead, use the simple prepend and append > functions to add new elements to the beginning or end of a sequence, > respectively: > > (append [1 2] 3 ) ;=> [1 2 3 ] > > ( > append [1 2] 3 4) ;=> [1 2 3 4] > > > ( > prepend 3 [2 1]) ;=> [ 3 2 1] > > ( > prepend 4 3 [2 1]) ;=> [4 3 2 1] > Both <code > style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation > > > -- > 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. > > -- > 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. > > -- > 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. -- 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.