Why conj and cons has different arguments order - clojure

In conj, the original collection is the first argument, in cons, it's the second argument.
I'm new to clojure, this seems a bit confusing. This two function has similar behavior, but why is the arguments order different, is it purposely designed like this?
(conj '(1 2 3) 4)
; => (4 1 2 3)
(cons 4 '(1 2 3))
; => (4 1 2 3)
I know this two functions are different, but why conj and cons place the original collection in different argument order.

cons traditionally means construct new object prepending first arg into second, and thats how the args are ordered.
Here's quote from LISP cons,
In LISP jargon, the expression "to cons x onto y" means to construct a
new object with (cons x y)
But conjoin normally is to append on given data-structure but depends on clojure data-type you use. Thats why collection comes first and then element to append.
Lets see the Vector;
user=> (type [3 5 7 11])
clojure.lang.PersistentVector
user=> (cons 1 [3 5 7 11])
(1 3 5 7 11)
user=> (conj [3 5 7 11] 13)
[3 5 7 11 13]
But for List, conjoin prepends as well,
user=> (type '(3 5 7 11))
clojure.lang.PersistentList
user=> (cons 1 '(3 5 7 11))
(1 3 5 7 11)
user=> (conj '(3 5 7 11) 13)
(13 3 5 7 11)
The doc for conj describes that as well.
user=> (doc conj)
-------------------------
clojure.core/conj
([coll x] [coll x & xs])
conj[oin]. Returns a new collection with the xs
'added'. (conj nil item) returns (item). The 'addition' may
happen at different 'places' depending on the concrete type.
nil
The order applies to any other functional languages as far as I know. Here's in scala;
scala> 1 +: Seq(1, 3, 5)
res1: Seq[Int] = List(1, 1, 3, 5)
scala> Seq(1, 3, 5) :+ 7
res2: Seq[Int] = List(1, 3, 5, 7)

The other answer gives a nice overview. I also wanted to point out the types resulting from conj and cons:
(cons 1 [2 3]) => <#clojure.lang.Cons (1 2 3)>
(conj [2 3] 9) => <#clojure.lang.PersistentVector [2 3 9]>
(cons 1 (quote (2 3))) => <#clojure.lang.Cons (1 2 3)>
(conj (quote (2 3)) 9) => <#clojure.lang.PersistentList (9 2 3)>
The type clojure.lang.Cons is a sequential type similar to (but not identical to) a clojure.lang.PersistentList:
(supers clojure.lang.Cons) =>
#{ clojure.lang.ASeq
clojure.lang.IHashEq
clojure.lang.IMeta
clojure.lang.IObj
clojure.lang.IPersistentCollection
clojure.lang.ISeq
clojure.lang.Obj
clojure.lang.Seqable
clojure.lang.Sequential
java.io.Serializable
java.lang.Iterable
java.lang.Object
java.util.Collection
java.util.List }
To simplify adding to the beginning or end of a sequence, you may be interested in the functions append and prepend.

Briefly, because they are opposite. In cons, the target element is the first one, and a collection becomes a the rest of the result sequence. In conj, the target element becomes a tail of the final collection.
I may recommend you to read the first chapter of SICP where cons and consing terms are described quite well.

Related

Why does clojure.core/rest output a list when input is a vector?

Why does clojure.core/rest output a list when input is a vector?
This creates an unexpected effect:
(conj [1 2 3] 4)
; => [1 2 3 4]
(conj (rest [1 2 3]) 4)
; => (4 2 3)
I know that "it calls seq on its argument" from the docs which creates this effect. I don't understand why this is the desired effect. As a naïve user, I would expect (rest [1 2 3]) to behave like (subvec [1 2 3] 1). I know I could just use subvec for my use case. For the sake of learning, I would like to understand the rationale of rest, and use cases where outputting a list is desirable (even when the input is a vector).
The output of rest is NOT a list, but a seq, which is an even lower level abstraction. From the official documentation for rest:
Returns a possibly empty seq of the items after the first. Calls seq on its
argument.
The confusion arises from the fact that both are printed between parens, but if you look closely, they are different:
user=> (list? (rest [1 2 3]))
false
user=> (seq? (rest [1 2 3]))
true
How it's a seq different from a list? seqs are implemented with an Interface that requires implementing first, rest and cons, but details are up to the collection implementation. For instance, vectors use their own implementation:
user=> (class (rest [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq
user=> (class (rest '(1 2 3)))
clojure.lang.PersistentList
List are an implementation that at least extends a basic Seq interface, and builds on top. For instance, clojure.lang.PersistentList implements the Counted interface which requires a constant-time version of count.
For a detailed description of the differences between Seqs and Lists, check these links:
Differences between a seq and a list
https://clojure.org/reference/sequences
You make a good case for rest on a vector returning a vector. The trouble is that rest is one of the fundamental operations on sequences, and a vector is not a sequence:
=> (seq? [1 2 3 4])
false
However, if rest can accept a seqable thing such as a vector, you could say that it ought to be able to return such.
What does it return?
=> (type (rest [1 2 3 4]))
clojure.lang.PersistentVector$ChunkedSeq
This gives every appearance of being a subvec wrapped in a seq call.
I know that "it calls seq on its argument"
That is correct. Seqs are implemented with an Interface (ISeq) that requires implementing first, rest and cons.
rest takes any Seq'able (any collection that implements ISequable). The reason for using this is efficiency and simplicity.
The way different collection works, the most efficient way of getting the first and rest is different.
Which is why when you convert one collection into a seq, it will come with the most efficient implementation on rest and the others.
I hope this was clear
I agree that this behavior is unexpected and counterintuitive. As a workaround, I created the append and prepend functions in the Tupelo library.
From the docs, we see examples:
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 prepend and append always return a vector result.

Composing a small list with elements among some candidate elements, where the inclusion of each element depends on an independent predicate?

Say I want to return a collection containing some subset of [1 2 3 4]. Whether 1 is included depends on w?, whether 2 is included depends on x?, 3 on y?, 4 on z?.
If I did
[(if (w?) 1) (if (x?) 2) (if (y?) 3) (if (z?) 4)]
And (x?) and (y?) evaluated to true, the others false, I'd end up with
[nil 2 3 nil]
but I want
[2 3]
Is there a canonical way to accomplish this? It's reminiscent of a list comprehension, but not quite the same.
Thanks
EDIT:
I supposed I could create a map {1 w? 2 x? 3 y? z 4?} and then reduce that by either consing or not consing each key depending on whether it's value function evaluates to true, but maybe there's a better way.
This would do what you want:
(defn f [conds vs]
(when (seq vs)
(let [[c1 & cr] conds
[v1 & vr] vs]
(if c1
(cons v1 (f cr vr))
(f cr vr)))))
Example:
(f [false true true false] [1 2 3 4])
=> (2 3)
(f [true true false true false true] [1 2 3 nil 4 5])
=> (1 2 nil 5)

Map with an accumulator in Clojure?

I want to map over a sequence in order but want to carry an accumulator value forward, like in a reduce.
Example use case: Take a vector and return a running total, each value multiplied by two.
(defn map-with-accumulator
"Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]."
[func accumulator collection]
(if (empty? collection)
nil
(let [[this-value new-accumulator] (func (first collection) accumulator)]
(cons this-value (map-with-accumulator func new-accumulator (rest collection))))))
(defn double-running-sum
[value accumulator]
[(* 2 (+ value accumulator)) (+ value accumulator)])
Which gives
(prn (pr-str (map-with-accumulator double-running-sum 0 [1 2 3 4 5])))
>>> (2 6 12 20 30)
Another example to illustrate the generality, print running sum as stars and the original number. A slightly convoluted example, but demonstrates that I need to keep the running accumulator in the map function:
(defn stars [n] (apply str (take n (repeat \*))))
(defn stars-sum [value accumulator]
[[(stars (+ value accumulator)) value] (+ value accumulator)])
(prn (pr-str (map-with-accumulator stars-sum 0 [1 2 3 4 5])))
>>> (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
This works fine, but I would expect this to be a common pattern, and for some kind of map-with-accumulator to exist in core. Does it?
You should look into reductions. For this specific case:
(reductions #(+ % (* 2 %2)) 2 (range 2 6))
produces
(2 6 12 20 30)
The general solution
The common pattern of a mapping that can depend on both an item and the accumulating sum of a sequence is captured by the function
(defn map-sigma [f s] (map f s (sigma s)))
where
(def sigma (partial reductions +))
... returns the sequence of accumulating sums of a sequence:
(sigma (repeat 12 1))
; (1 2 3 4 5 6 7 8 9 10 11 12)
(sigma [1 2 3 4 5])
; (1 3 6 10 15)
In the definition of map-sigma, f is a function of two arguments, the item followed by the accumulator.
The examples
In these terms, the first example can be expressed
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
In this case, the mapping function ignores the item and depends only on the accumulator.
The second can be expressed
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
... where the mapping function depends on both the item and the accumulator.
There is no standard function like map-sigma.
General conclusions
Just because a pattern of computation is common does not imply that
it merits or requires its own standard function.
Lazy sequences and the sequence library are powerful enough to tease
apart many problems into clear function compositions.
Rewritten to be specific to the question posed.
Edited to accommodate the changed second example.
Reductions is the way to go as Diego mentioned however to your specific problem the following works
(map #(* % (inc %)) [1 2 3 4 5])
As mentioned you could use reductions:
(defn map-with-accumulator [f init-value collection]
(map first (reductions (fn [[_ accumulator] next-elem]
(f next-elem accumulator))
(f (first collection) init-value)
(rest collection))))
=> (map-with-accumulator double-running-sum 0 [1 2 3 4 5])
(2 6 12 20 30)
=> (map-with-accumulator stars-sum 0 [1 2 3 4 5])
("*" "***" "******" "**********" "***************")
It's only in case you want to keep the original requirements. Otherwise I'd prefer to decompose f into two separate functions and use Thumbnail's approach.

Weird behaviour of conj

I was trying some Clojure, but now puzzled about the behavior of the "conj".
See the exaples below:
user=> (conj [1 2 3] 4)
[1 2 3 4]
Above is expected.
But now, if I do the below:
user=> (conj (reverse [1 2 3]) 4)
(4 3 2 1)
It returns (4 3 2 1). But I guess it should have returned (3 2 1 4). So, what am I missing here?
reverse returns a list.
(reverse [1 2 3])
=> (3 2 1)
conj has the behavior of adding something to a collection as cheaply as possible. For vectors, it'd be appending. For lists, it'd be pre-pending.
For example:
(conj '(1 2 3) 4)
=> (4 1 2 3)

Is there an equivalent for the Zip function in Clojure Core or Contrib?

In Clojure, I want to combine two lists to give a list of pairs,
> (zip '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
In Haskell or Ruby the function is called zip. Implementing it is not difficult, but I wanted to make sure I wasn't missing a function in Core or Contrib.
There is a zip namespace in Core, but it is described as providing access to the Zipper functional technique, which does not appear to be what I am after.
Is there an equivalent function for combining 2 or more lists, in this way, in Core?
If there is not, is it because there is an idiomatic approach that renders the function unneeded?
(map vector '(1 2 3) '(4 5 6))
does what you want:
=> ([1 4] [2 5] [3 6])
Haskell needs a collection of zipWith (zipWith3, zipWith4, ...) functions, because they all need to be of a specific type; in particular, the number of input lists they accept needs to be fixed. (The zip, zip2, zip3, ... family can be regarded as a specialisation of the zipWith family for the common use case of tupling).
In contrast, Clojure and other Lisps have good support for variable arity functions; map is one of them and can be used for "tupling" in a manner similar to Haskell's
zipWith (\x y -> (x, y))
The idiomatic way to build a "tuple" in Clojure is to construct a short vector, as displayed above.
(Just for completeness, note that Haskell with some basic extensions does allow variable arity functions; using them requires a good understanding of the language, though, and the vanilla Haskell 98 probably doesn't support them at all, thus fixed arity functions are preferrable for the standard library.)
(partition 2 (interleave '(1 2 3) '(4 5 6)))
=> ((1 4) (2 5) (3 6))
or more generally
(defn zip [& colls]
(partition (count colls) (apply interleave colls)))
(zip '( 1 2 3) '(4 5 6)) ;=> ((1 4) (2 5) (3 6))
(zip '( 1 2 3) '(4 5 6) '(2 4 8)) ;=> ((1 4 2) (2 5 4) (3 6 8))
(map vector [1 2 3] [4 5 6])
to give you exactly what you wanted, mapping list across the two lists will give you a list of lists like in your example. I think that many Clojurians would tend to use vectors for this though it will work with anything. and the inputs do not need to be the same type. map creates seqs from them and then maps the seqs so any seq'able input will work fine.
(map list '(1 2 3) '(4 5 6))
(map list [1 2 3] '(4 5 6))
(map hash-map '(1 2 3) '(4 5 6))
(map hash-set '(1 2 3) '(4 5 6))
The built-in way would simply be the function 'interleave':
(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]
There is a function called zipmap, that may have the similar effect,
(zipmap (1 2 3)(4 5 6))
The ouput is as fllows:
{3 6, 2 5, 1 4}
#(apply map list %) transposes a matrix just like the Python zip* function. As a macro definition:
user=> (defmacro py-zip [lst] `(apply map list ~lst))
#'user/py-zip
user=> (py-zip '((1 2 3 4) (9 9 9 9) (5 6 7 8)))
((1 9 5) (2 9 6) (3 9 7) (4 9 8))
user=> (py-zip '((1 9 5) (2 9 6) (3 9 7) (4 9 8)))
((1 2 3 4) (9 9 9 9) (5 6 7 8))