Clojure - Unknown number of arguments in a function - clojure

I have a function
(defn x [w]
(let [[w1 w2 w3] w]
(println w1)
(println w2)
(println w3)))
If I call the function
(x [[1 1] [2 2] [3 3]])
=> [1 1]
[2 2]
[3 3]
which is what I expect
Is there a way to generalise this? In this case I knew that w was a vector containing 3 vectors so I know to have [w1 w2 w3] If w was then a vector of 4 vectors, the last vector would not be set to anything
What I want is where w is a vector of n vectors and then in the let of the function set them to [w1 w2 w3 ... wn]? (note doesn't necessarily have to be w1, w2, ... wn)
The println are just there for debugging so not that important for the function
Any help would be much appreciated.

(defn x [ws]
(dorun (map println ws)))
For example,
(x [[1 1] [2 2] [3 3]])
[1 1]
[2 2]
[3 3]
=> nil
The map applies println to each of the ws in turn, returning
the nil results as a sequence, on demand (lazily).
The dorun demands the whole sequence, discarding it as it goes,
returning nil.
If you want to see the sequence, replace dorun with doall:
(defn x [ws]
(doall (map println ws)))
=> (x [[1 1] [2 2] [3 3]])
[1 1]
[2 2]
[3 3]
=> (nil nil nil)
A more concise alternative to the former is
(defn x [ws]
(doseq [w ws] (println w)))
... and to the latter is
(defn x [ws]
(for [w ws] (println w)))

Related

clojure-spec: Unable to get function's postcondition right

I'm trying clojure spec on a simple function that computes the "neighbours" of a (row,col) position in a square matrix. For example for the 4x4 matrix given below, the neighbours of cell (1,1) shall be: (0,1), (1,0), (1,2), (2,1). The neighbours of cell (4,3), which is not even in the matrix' range, shall be (3,3) etc.
The function's input is the size of the matrix and the (row,col) of the position of interest. The output is a collection of (row,col) of the neighbours. This collection can be empty if there are no neighbours.
This problem can be found in "The Joy of Clojure, 2nd editions, page 94; but this code is modified because the original was too compact for me. Then I tried to spec it and check the spec in the :pre and :post parts.
However, I don't get the :post part to work. When I run the test cases, I get:
java.lang.ClassCastException: java.lang.Boolean cannot be cast
to clojure.lang.IFn
What to change?
(require '[clojure.spec.alpha :as s]
'[clojure.test :as t])
; ===
; Specs
; ===
(s/def ::be-row-col
(s/coll-of integer? :count 2 :kind sequential?))
(s/def ::be-square-matrix-size
(s/and integer? #(<= 0 %)))
(s/def ::be-row-col-vector
(s/and (s/coll-of ::be-row-col) (s/int-in-range? 0 5 #(count %))))
; ===
; Function of interest
; ===
(defn neighbors [sqmsz rc]
{:pre [(s/valid? ::be-row-col rc)
(s/valid? ::be-square-matrix-size sqmsz)]
:post [(s/valid? ::be-row-col-vector %)]
}
(let [ cross [[-1 0] [1 0] [0 -1] [0 1]]
in-sq-matrix? (fn [x]
(and (<= 0 x) (< x sqmsz)))
in-sq-matrix-rc? (fn [rc]
(every? in-sq-matrix? rc))
add-two-rc (fn [rc1 rc2]
(vec (map + rc1 rc2)))
get-rc-neighbors (fn [rc]
(map (partial add-two-rc rc) cross)) ]
(filter in-sq-matrix-rc? (get-rc-neighbors rc))))
; ===
; Put a collection of [row col] into an expected form
; ===
; this is used to run the test code
(defn formify [rc-coll]
(let [ cmp (fn [rc1 rc2]
(let [ [r1 c1] rc1
[r2 c2] rc2 ]
(cond (< r1 r2) -1 ; sort by row
(> r1 r2) +1
(< c1 c2) -1 ; then by column
(> c1 c2) +1
true 0))) ]
(vec (sort cmp rc-coll))))
; ===
; Testing
; ===
(defn test-nb [ sqmsz rc expected txt ]
(do
(t/is (= (formify (neighbors sqmsz rc)) expected) txt)
))
(test-nb 0 [0 0] [] "Zero-size matrix, outside #1")
(test-nb 0 [1 1] [] "Zero-size matrix, outside #2")
(test-nb 1 [0 0] [] "One-size matrix, inside")
(test-nb 1 [1 0] [[0 0]] "One-size matrix, outside")
(test-nb 5 [0 0] [[0 1] [1 0]] "Testing top left")
(test-nb 5 [1 0] [[0 0] [1 1] [2 0]] "Testing left edge")
(test-nb 5 [1 1] [[0 1] [1 0] [1 2] [2 1]] "Testing middle #1")
(test-nb 5 [2 2] [[1 2] [2 1] [2 3] [3 2]] "Testing middle #2")
(test-nb 5 [3 3] [[2 3] [3 2] [3 4] [4 3]] "Testing middle #3")
(test-nb 5 [4 4] [[3 4] [4 3]] "Testing btm right")
(test-nb 5 [5 5] [] "Testing outside #1")
(test-nb 5 [5 4] [[4 4]] "Testing outside #2")
(test-nb 5 [4 3] [[3 3] [4 2] [4 4]] "Testing btm edge")
You're just missing the # prefix to make your anonymous function in the :post condition. The post condition needs to be a function that can take the output of the subject function's invocation.
:post [#(s/valid? ::be-row-col-vector %)]
Could also be rewritten as:
:post [(fn [o] (s/valid? ::be-row-col-vector o))]
But depending on your use case, you may want to look into function specs and instrument as an alternative to :pre and :post conditions. I wrote more examples here.

How to split an input sequence according to the input number given

I'm writing a clojure function like:
(defn area [n locs]
(let [a1 (first locs)]
(vrp (rest locs))))
I basically want to input like: (area 3 '([1 2] [3 5] [3 1] [4 2])) But when I do that it gives me an error saying Wrong number of args (1) passed. But I'm passing two arguments.
What I actually want to do with this function is that whatever value of n is inputted (say 3 is inputted), then a1 should store [1 2], a2 should store [3 5], a3 should store ([3 1] [4 2]). What should I add in the function to get that?
clojue's build in split-at function is very close to solving this. It splits a sequence "at" a given point. So if we first split the data apart and then wrap the second half in a list and concatenate it back together again it should solve this problem:
user> (let [[start & end] (split-at 2 sample-data)]
(concat start end))
([1 2] [3 5] ([3 1] [4 2]))
the & before end in let causes the last item to be rolled up in a list. It's equivalent to:
user> (let [[start end] (split-at 2 sample-data)]
(concat start (list end)))
([1 2] [3 5] ([3 1] [4 2]))
If I recklessly assume you have some function called vrp that needs data in this form then you could finish your function with something like this:
(defn area [n locs]
(let [[start end] (split-at (dec n) sample-data)
a (concat start (list end))]
(apply vrp a)))
Though please forgive me to making wild guesses as to the nature of vrp, I could be totally off base here.

Clojure: understaning the binding in a doseq

I understand the following snippet of code and its corresponding output
(let [ [x y] (map list [1 2] [3 4])] (prn x) (prn y))
(1 3)
(2 4)
nil
Now the following output confuses me:
(doseq [ [x y] (map list [1 2] [3 4])] (prn x y))
1 3
2 4
nil
I think in the above snippet x will get bound to [1 3] and y will get bound to [2 4] so the output should be"
1 2
3 4
nil
The binding is pulling out the individual elements inside the larger single element in the nesting. The map creates a list ((1 3) (2 4) so the element 1 3 is first and thus that is what the doseq outputs: this is "destructuring" and the x and y are both bound from inside a single element of the list. Thus x and y are 1 and 3, and then 2 and 4.
Note also that this is the same binding that occurs in a for and the destructuring works for all sequence types.
Let's isolate the source of your confusion.
(map list [1 2] [3 4])
evaluates to
((1 3) (2 4))
So your first example
(let [[x y] (map list [1 2] [3 4])] (prn x) (prn y))
... is equivalent to
(let [[x y] [[1 3] [2 4]]] (prn x) (prn y))
... or, printing slightly differently
(let [[x y] [[1 3] [2 4]]] (prn [x y]))
... which simplifies to
(let [z [[1 3] [2 4]]] (prn z))
... producing, as expected,
; [[1 3] [2 4]]
; nil
So far, so good.
If we boil down the confusing example,
(doseq [ [x y] (map list [1 2] [3 4])] (prn x y))
... in the same way, we get, taking the liberty of printing each z whole,
(doseq [z [[1 3] [2 4]]] (prn z))
which fairly clearly produces the observed order:
[1 3]
[2 4]
nil
The difference is that the doseq binds z to each successive vector in [[1 3] [2 4]], so we don't see an enclosing [ ... ], whereas the let binds z once to the whole thing.

How to write a Clojure function that returns a list of adjacent pairs?

I'm trying to write a function adjacents that returns a vector of a sequence's adjacent pairs. So (adjacents [1 2 3]) would return [[1 2] [2 3]].
(defn adjacents [s]
(loop [[a b :as remaining] s
acc []]
(if (empty? b)
acc
(recur (rest remaining) (conj acc (vector a b))))))
My current implementation works for sequences of strings but with integers or characters the REPL outputs this error:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:494)
The problem here is in the first evaluation loop of (adjacents [1 2 3]), a is bound to 1 and b to 2. Then you ask if b is empty?. But empty? works on sequences and b is not a sequence, it is a Long, namely 2. The predicate you could use for this case here is nil?:
user=> (defn adjacents [s]
#_=> (loop [[a b :as remaining] s acc []]
#_=> (if (nil? b)
#_=> acc
#_=> (recur (rest remaining) (conj acc (vector a b))))))
#'user/adjacents
user=> (adjacents [1 2 3 4 5])
[[1 2] [2 3] [3 4] [4 5]]
But, as #amalloy points out, this may fail to give the desired result if you have legitimate nils in your data:
user=> (adjacents [1 2 nil 4 5])
[[1 2]]
See his comment for suggested implementation using lists.
Note that Clojure's partition can be used to do this work without the perils of defining your own:
user=> (partition 2 1 [1 2 3 4 5])
((1 2) (2 3) (3 4) (4 5))
user=> (partition 2 1 [1 2 nil 4 5])
((1 2) (2 nil) (nil 4) (4 5))
Here is my short answer. Everything becomes a vector, but it works for all sequences.
(defn adjacent-pairs [s]
{:pre [(sequential? s)]}
(map vector (butlast s) (rest s)))
Testing:
user=> (defn adjacent-pairs [s] (map vector (butlast s) (rest s)))
#'user/adjacent-pairs
user=> (adjacent-pairs '(1 2 3 4 5 6))
([1 2] [2 3] [3 4] [4 5] [5 6])
user=> (adjacent-pairs [1 2 3 4 5 6])
([1 2] [2 3] [3 4] [4 5] [5 6])
user=>
This answer is probably less efficient than the one using partition above, however.

What does the while modifier mean in clojure?

The following shows that the modifier "while" means the iterate will stop once an element match the check:
=> (for [x [3 2 3 1] :while (< x 3)] x)
()
However why the following not stop iterating ? it should return an empty list in my (wrong) understanding.
=> (for [x [3 2 3 1] y [:a :b] :while (< x 3)] [x y])
([2 :a] [2 :b] [1 :a] [1 :b])
Actually it turns out that there is no difference between the "when" and the "while" modifier in this case.
=> (for [x [3 2 3 1] y [:a :b] :when (< x 3)] [x y])
([2 :a] [2 :b] [1 :a] [1 :b])
How that happen ?
The :while and :when modifiers are always checked after the binding immediately preceding them, and only apply to the iteration of that loop. If you want to stop binding new xs, you need to put the :while after the x clause, not the y clause.