Why do `vector` and `[...]` sometimes behave differently in Clojure? - vector

In Clojure, the square brackets are a shorthand for defining vectors:
user=> (vector 'a 'b 'c)
[a b c]
user=> ['a 'b 'c]
[a b c]
The documentation page for vector speaks of the long way and the short way of defining vectors.
However, in defn and doseq there seems to be a difference.
user=> (doseq [x (range 1 4)] (printf "%d\n" x))
1
2
3
nil
user=> (doseq (vector 'x (range 1 4)) (printf "%d\n" x))
IllegalArgumentException doseq requires a vector for its binding in user:1 clojure.core/doseq (core.clj:2935)
What accounts for this difference? Are the square brackets given special status in the reader, or do they sugar some particular form?

vector is evaluated after macroexpansion, while [] is evaluated at read time, before macros are expanded. In your second case, the doseq macro does not see a vector, it sees a list starting with the symbol vector, since macros are expanded before regular functions are evaluated.

Related

How to protect vector from resizing?

So I am going through Practical Common Lisp once again and I cannot really understand how to create a vector with constant size.
According to the book:
However, even a vector with a fill pointer isn't completely resizable. The vector *x* can hold at most five elements. To make an arbitrarily resizable vector, you need to pass MAKE-ARRAY another keyword argument: :adjustable.
However when I use (vector-push-extend) I can extend my initial vector even when I set :adjustable nil (or leave it default).
(vector-push 'a *x*) ;; 0
(vector-push 'b *x*) ;; 1
(vector-push 'c *x*) ;; 2
(vector-push 'd *x*) ;; 3
(vector-push 'e *x*) ;; 4
*x* ;; #(A B C D E)
(vector-push 'f *x*) ;; NIL
*x* ;; #(A B C D E)
(vector-push-extend 'f *x*) ;; 5
*x* ;; #(A B C D E F)
I assumed that (vector-push-extend) cannot resize array which is not :adjustable? What is the correct way of creating non-dynamic (non-adjustable) array?
The behavior is implementation specific.
The Common Lisp specification says:
There is no specified way to create an array for which adjustable-array-p definitely returns false.
An implementation may make vectors adjustable, even though the :adjustable argument to make-array is given as nil.
To see if an array object is actually adjustable, one needs to call adjustable-array-p.
The Common Lisp standard says that a vector is expressly adjustable (and thus also actually adjustable if it was requested to be so. If it wasn't request, the vector can still be adjustable, actually adjustable.
So the :adjustable nil arg is just telling Lisp, that it can make the vector non-adjustable, if possible.
Here in SBCL:
1) A normal vector is not adjustable:
* (make-array 5)
#(0 0 0 0 0)
* (adjustable-array-p *)
NIL
2) A vector with a fill-pointer is actually adjustable in SBCL:
* (make-array 5 :fill-pointer 0)
#()
* (adjustable-array-p *)
T
3) A vector with a fill-pointer is actually adjustable in SBCL, even though the :adjustable arg was given as nil:
* (make-array 5 :fill-pointer 0 :adjustable nil)
#()
* (adjustable-array-p *)
T
That's in SBCL. In LispWorks 2) and 3) would not be actually adjustable.
The specification of make-array says that it is implementation dependent whether an array with :adjustable nil is actually adjustable. In the notes, it goes on to say:
There is no specified way to create an array for which adjustable-array-p definitely returns false.
So, it really depends on the implementation.
The correct way is to use vector-push if you do not want to extend.

Computing linear combination of vectors in Common Lisp

I'm working on some numerical computations in Common Lisp and I need to compute a linear combination of several vectors with given numerical coefficients. I'm rewriting a piece of Fortran code, where this can be accomplished by res = a1*vec1 + a2*vec2 + ... + an*vecn. My initial take in CL was to simply write each time something like:
(map 'vector
(lambda (x1 x2 ... xn)
(+ (* x1 a1) (* x2 a2) ... (* xn an)))
vec1 vec2 ... vecn)
But I soon noticed that this pattern would recur over and over again, and so started writing some code to abstract it away. Because the number of vectors and hence the number of lambda's arguments would vary from place to place, I figured a macro would be required. I came up with the following:
(defmacro vec-lin-com (coefficients vectors &key (type 'vector))
(let ((args (loop for v in vectors collect (gensym))))
`(map ',type
(lambda ,args
(+ ,#(mapcar #'(lambda (c a) (list '* c a)) coefficients args)))
,#vectors)))
Macroexpanding the expression:
(vec-lin-com (10 100 1000) (#(1 2 3) #(4 5 6) #(7 8 9)))
yields the seemingly correct expansion:
(MAP 'VECTOR
(LAMBDA (#:G720 #:G721 #:G722)
(+ (* 10 #:G720) (* 100 #:G721) (* 1000 #:G722)))
#(1 2 3) #(4 5 6) #(7 8 9))
So far, so good...
Now, when I try to use it inside a function like this:
(defun vector-linear-combination (coefficients vectors &key (type 'vector))
(vec-lin-com coefficients vectors :type type))
I get a compilation error stating essentially that The value VECTORS is not of type LIST. I'm not sure how to approach this. I feel I'm missing something obvious. Any help will be greatly appreciated.
You've gone into the literal trap. Macros are syntax rewriting so when you pass 3 literal vectors in a syntax list you can iterate on them at compile time, but replacing it with a bindnig to a list is not the same. The macro only gets to see the code and it doesn't know what vectors will eventually be bound to at runtime when it does its thing. You should perhaps make it a function instead:
(defun vec-lin-com (coefficients vectors &key (type 'vector))
(apply #'map
type
(lambda (&rest values)
(loop :for coefficient :in coefficients
:for value :in values
:sum (* coefficient value)))
vectors))
Now you initial test won't work since you passed syntax and not lists. you need to quote literals:
(vec-lin-com '(10 100 1000) '(#(1 2 3) #(4 5 6) #(7 8 9)))
; ==> #(7410 8520 9630)
(defparameter *coefficients* '(10 100 1000))
(defparameter *test* '(#(1 2 3) #(4 5 6) #(7 8 9)))
(vec-lin-com *coefficients* *test*)
; ==> #(7410 8520 9630)
Now you could make this a macro, but most of the job would have been done by the expansion and not the macro so basically you macro would expand to similar code to what my function is doing.
Remember that macros are expanded at compile-time, so the expression ,#(mapcar #'(lambda (c a) (list '* c a)) coefficients args) has to be meaningful at compile-time. In this case, all that mapcar gets for coefficients and args are the symbols coefficients and vectors from the source code.
If you want to be able to call vec-lin-com with an unknown set of arguments (unknown at compile-time, that is), you'll want to define it as a function. It sounds like the main problem you're having is getting the arguments to + correctly ordered. There's a trick using apply and map to transpose a matrix that may help.
(defun vec-lin-com (coefficients vectors)
(labels
((scale-vector (scalar vector)
(map 'vector #'(lambda (elt) (* scalar elt)) vector))
(add-vectors (vectors)
(apply #'map 'vector #'+ vectors)))
(let ((scaled-vectors (mapcar #'scale-vector coefficients vectors)))
(add-vectors scaled-vectors))))
This isn't the most efficient code in the world; it does a lot of unnecessary consing. But it is effective, and if you find this to be a bottleneck you can write more efficient versions, including some that can take advantage of compile-time constants.

why clojure conj acts different between vector and map

> (conj [0] 1 2 3)
[0 1 2 3]
> (conj {:a "ei"} {:b "bi"})
{:b "bi", :a "ei"}
>
See, when it acts on vector, it puts 1,2,3 at end of it.
Whereas it put :b "bi" in front of :a map k-v pair
Why is this?
thanks
As with many hashed maps implementations, Clojure's hashed maps do not sort their entries, not retain the order in which they were inserted. This allows for better performance.
Note that conj does not have general ordering semantics either (it has ordering semantics for some concrete types, such as vectors).
You don't have to go as far as maps to get inconsistent behaviour from conj:
(conj [1] 2) ; [1 2]
(conj (list 1) 2) ; (2 1)
Hash maps have no defined order. But, for any map,
the seq of entries will always be the same
the vals and keys will be in consistent order.
Thus, for map m,
(= (keys m) (map key m))
(= (vals m) (map val m))
(= m (zipmap (keys m) (vals m)))
Currently, this sequence seems to be independent of insertion order. I tested this on sets by randomly shuffling random integers.

Clojure map. Pass function multiple parameters

I'm looking for a way how to use map function in more custom way. If there is a different function for what I'm trying to achieve, could you please let me know this.
;lets say i have addOneToEach function working as bellow
(defn plusOne[singleInt]
(+ 1 singleInt))
(defn addOneToEach[intCollection] ;[1 2 3 4]
(map plusOne intCollection)) ;=>(2 3 4 5)
;But in a case I would want to customly define how much to add
(defn plusX[singleInt x]
(+ x singleInt))
(defn addXToEach[intCollection x] ;[1 2 3 4]
;how do I use plusX here inside map function?
(map (plusX ?x?) intCollection)) ;=>((+ 1 x) (+ 2 x) (+ 3 x) (+ 4 x))
I'm not looking for a function that adds x to each in the collection, but a way to pass extra arguments to the function that map is using.
another option to the already mentioned would be partial (note that in the example the order of the params does not matter, since you just add them, but partial binds them from left to right, so beware):
user=> (doc partial)
-------------------------
clojure.core/partial
([f] [f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more])
Takes a function f and fewer than the normal arguments to f, and
returns a fn that takes a variable number of additional args. When
called, the returned function calls f with args + additional args.
nil
user=> (defn plus-x [x i] (+ x i))
#'user/plus-x
user=> (map (partial plus-x 5) [1 2 3])
(6 7 8)
There are several ways to go about it. One is using an explicit local function via letfn:
(defn add-x-to-each [ints x]
(letfn [(plus-x [i]
(+ i x))]
(map plus-x ints)))
For this small piece of code this is probably overkill and you can simply streamline it via an anonymous function:
(defn add-x-to-each [ints x]
(map #(+ % x) ints))
Both of these solutions basically apply the use of a closure which is an important concept to know: it boils down to defining a function dynamically which refers to a variable in the environment at the time the function was defined. Here we defer the creation of plus-x (or the anonymous) function until x is bound, so plus-x can refer to whatever value is passed in to add-x-to-each.
You almost got it right.
There are several possible ways:
1.
(defn addXToEach[intCollection x]
(map #(plusX % x) intCollection))
#(%) means same as (fn [x] (x)) (be aware that x is being evaluated here).
2.
(defn addXToEach[intCollection x]
(map (fn [item] (plusX item x)) intCollection))
3.
(defn addXToEach[intCollection x]
(map #(+ % x) intCollection))
and then you don't have to define your plusX function.
Hope it helps!
You are applying map to one collection, so the function that map applies must take one argument. The question is, how is this function to be composed?
The function
(defn plusOne [singleInt]
(+ 1 singleInt))
... works. It is otherwise known as inc.
But the function
(defn plusX [singleInt x]
(+ x singleInt))
... doesn't work, because it takes two arguments. Given a number x, you want to return a function that adds x to its argument:
(defn plusX [x]
(fn [singleInt] (+ x singleInt))
You can use a function returned by plusX in the map.
It is when you compose such a function that you can use extra arguments. This kind of function, composed as an expression involving captured data, is called a closure.
For example, (plusX 3) is a function that adds 3 to its argument.
(map (plusX 3) stuff)
;(4 5 6 7)
As you see, you don't need to name your closure.
Specifically for + the following will also work:
(map + (repeat 4) [3 4 9 0 2 8 1]) ;=> (7 8 13 4 6 12 5)
Of course, instead '4' put your number, or wrap with (let [x 4] ...) as suggested above.
It might not be the most performant, although, I guess.

Clojure hashmaps as generalized vectors

I would like to use Clojure hashmaps to define generalized vectors. In this picture, the hashmap {:x 3 :y 2 :z (- 3)} represents the symbolic expression 3x + 2y - 3z.
I would like a function gen+ which acts as an addition operation on hashmaps, and which satisfies the following constraints:
Applying gen+ to two hashmaps with overlapping keys returns a hashmap with those key values summed. e.g.,
(gen+ {:x 1} {:x 2})
;= {:x 3}
Applying gen+ to two hashmaps with distinct keys returns a hashmap with those key-values combined. e.g.,
(gen+ {:x 1} {:y 2})
;= {:x 1 :y 2}
The empty hashmap {} is an additive identity for the gen+ function. e.g.,
(gen+ {:x 1} {})
:= {:x 1}
By the above constraints, any hashmap with zero entries is also an additive identity. For example, {:z 0}. Owing to this redundancy, the gen+ function should always return hashmaps without any 0 values. e.g.,
(gen+ {:x 1 :y 0} {:z 0})
;= {:x 1}
Clojure interprets missing keys as having value nil, rather than 0, as with ({:x 3} :y) ;= nil. Consequently, gen+ should treat nil values the same way as 0. e.g.,
(gen+ {:x 1 :y 0} {:x nil :y nil})
{:x 1}
My Question: How can we write a function gen+ which satisfies the above constraints? Once this is in place, is it possible to overload the + operator with the gen+ function, enabling elementary addition with hashmaps?
It should be apparent why this formalism treats hashmaps as generalized vectors. Clojure interprets a vector like [x0 x1 x2] almost the same as the hashmap {:0 x0 :1 x1 :2 x2}, with a slight difference that I don't quite understand. Consequently, if we apply gen+ to two vectors, then it should be effectively the same as + applied to them. This empowers us to easily work with sparse vectors, as well as add vectors of different sizes. e.g.,
(gen+ [0 0 0 4] [0 0 0 0 0 0 0 0 0 9])
;= {:4 4 :9 9}
Here's what I don't understand about hashmaps and vectors. If I call a hashmap as a function, I need to apply a key argument like :2. On the other hand, if I call a vector as a function, I need to apply an index argument like 2. e.g.,
({:2 2} :2)
;= 2
([0 1 2] 2]
;= 2
Even if you can't help with the gen+ function, could you please explain why hashmaps and vectors behave differently when called as functions?
The answer to you first question is to use merge-with See http://clojuredocs.org/clojure_core/clojure.core/merge-with
From the docs:
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(s)
from the latter (left-to-right) will be combined with the mapping in
the result by calling (f val-in-result val-in-latter).
You can then write a function to combine the merged values (maybe +). Then toss the nil and 0 values.
Overloading + is not really a good idea in Clojure as it isn't really overloading but replacing.
The difference between a map and vector is a like an array while a map is more a dictionary of key value pairs. Both structures are also functions of them members. For a vector/array whose members are access by offset, it makes sense for it to accept an offset. For a map/dictionary whose members as accessed by key, it makes sense for it to accept a key.
This will first remove the nil and 0 values and then add the maps with merge-with, as suggested by M Smith:
(defn filter-vals
[pred m]
(into {} (filter (fn [[k v]] (pred v))
m)))
(defn gen+
[m1 m2]
(letfn [(keep-val? [val]
(and (not (nil? val))
(not (zero? val))))]
(merge-with +
(filter-vals keep-val? m1)
(filter-vals keep-val? m2))))
You need to filter out any nils before you start adding - otherwise you'll eventually end up trying to add nil to a number, which is an error. However, it's possible for the gen+ I outlined to return an entry with a 0 value (consider (gen+ {:x 1} {:x -1})).
If that's possible based on your inputs, and needs to be avoided, you need to add another filter after the merge:
(defn gen+
[m1 m2]
(letfn [(keep-val? [val]
(and (not (nil? val))
(not (zero? val))))]
(->> (merge-with +
(filter-vals keep-val? m1)
(filter-vals keep-val? m2))
(filter-vals keep-val?))))
And, finally, here's a version that can handle a variable number of input maps:
(defn gen+
[& maps]
(letfn [(keep-val? [val]
(and (not (nil? val))
(not (zero? val))))]
(->> (apply merge-with
+
(map #(filter-vals keep-val? %) maps))
(filter-vals keep-val?))))
So, for instance:
(gen+ {:x 1} {:x 3} {:x 4 :y 5}) ;=> {:x 8, :y 5}
Regarding the difference between maps and vectors, think of it this way: maps are functions from keys to values, whereas vectors are functions from indices to values. In both cases if you have a "key" (which for a vector is the index) you can use that to look up the associated value.
I agree with the answers and comments you've gotten so far about overloading clojure.core/+ (I don't recommend it); that said, here's one way to sort of do it, with plenty of caveats:
(ns overload.example
(:refer-clojure :exclude [+])
(:require [clojure.core :as clj]))
(in-ns 'overload.example)
(defn gen+ ...)
(defn + [& xs]
(if (every? number? xs)
(reduce clj/+ 0 xs)
(apply gen+ xs)))

Resources