I am loading forms from a file using slurp, read, and cons'ing them together to recursively read all forms into a collection. Then wish to pass this into scriptjure's (js [& forms]) function, which expects a (list?), but (cons) gives me a Cons classed-object. How may I convert (class (cons 1 '(2 3 4 5))) to be IPersistentList? Thanks!
Use (apply list x) to create a list from sequence x :
user=> (class (apply list (cons 1 '(2 3 4 5 6))))
clojure.lang.PersistentList
Alternatively, if you start with a list and then conj forms onto it, you'll end up with a list:
user=> (class (conj (list 1 2 3) 4))
clojure.lang.PersistentList
No need for cons in this case since conj, given a list, returns a list.
Related
I'm currently learning Clojure, and I'm trying to learn how to do things the best way. Today I'm looking at the basic concept of doing things on a sequence, I know the basics of map, filter and reduce. Now I want to try to do a thing to pairs of elements in a sequence, and I found two ways of doing it. The function I apply is println. The output is simply 12 34 56 7
(def xs [1 2 3 4 5 6 7])
(defn work_on_pairs [xs]
(loop [data xs]
(if (empty? data)
data
(do
(println (str (first data) (second data)))
(recur (drop 2 data))))))
(work_on_pairs xs)
I mean, I could do like this
(map println (zipmap (take-nth 2 xs) (take-nth 2 (drop 1 xs))))
;; prints [1 2] [3 4] [5 6], and we loose the last element because zip.
But it is not really nice.. My background is in Python, where I could just say zip(xs[::2], xs[1::2]) But I guess this is not the Clojure way to do it.
So I'm looking for suggestions on how to do this same thing, in the best Clojure way.
I realize I'm so new to Clojure I don't even know what this kind of operation is called.
Thanks for any input
This can be done with partition-all:
(def xs [1 2 3 4 5 6 7])
(->> xs
(partition-all 2) ; Gives ((1 2) (3 4) (5 6) (7))
(map (partial apply str)) ; or use (map #(apply str %))
(apply println))
12 34 56 7
The map line is just to join the pairs so the "()" don't end up in the output.
If you want each pair printed on its own line, change (apply println) to (run! println). Your expected output seems to disagree with your code, so that's unclear.
If you want to dip into transducers, you can do something similar to the threading (->>) form of the accepted answer, but in a single pass over the data.
Assuming
(def xs [1 2 3 4 5 6 7])
has been evaluated already,
(transduce
(comp
(partition-all 2)
(map #(apply str %)))
conj
[]
xs)
should give you the same output if you wrap it in
(apply println ...)
We supply conj (reducing fn) and [] (initial data structure) to specify how the reduce process inside transduce should build up the result.
I wouldn't use a transducer for a list that small, or a process that simple, but it's good to know what's possible!
The following clojure code dedupe elements in a vector:
user> (partition-by identity [1 2 2 3 3 3 4 2 2 1 1 1])
((1) (2 2) (3 3 3) (4) (2 2) (1 1 1))
How does it accomplish the dedupe?
How can I see, step by step, how the resulting collection is built?
If you haven't seen it yet, be sure to bookmark The Clojure CheatSheet.
Clicking on partition-by takes you ClojureDocs.org with good info & examples.
Click in the upper-right to see the Clojure source code. Look at the 2nd arity that takes a function f and a collection coll:
([f coll]
(lazy-seq
(when-let [s (seq coll)]
(let [fst (first s)
fv (f fst)
run (cons fst (take-while #(= fv (f %)) (next s)))]
(cons run (partition-by f (seq (drop (count run) s))))))))
So fst is the first item in the collection, and fv is the transformed value using the function f. It then consumes all items that match fv, at which point it recurses with the first non-matching item.
(cons 1 (list 2 3)) returns a clojure.lang.cons. How can I convert it to clojure.lang.PersistentList?
Instead of calling cons and trying to convert the result, use conj:
(conj (list 2 3) 1)
=> (1 2 3)
(type (conj (list 2 3) 1))
=> clojure.lang.PersistentList
Clojure: how to convert cons to list
Don't!
Clojure is built upon extensible abstractions. One of the most important is the sequence.
I can think of no reason why you would want to convert a cons into a listor vice versa. They are both sequences and nothing much else. What you can do with one you can do with the other.
The above takes forward Leetwinski's comment on the question.
You can apply the contents of the returned sequence to the list function:
(apply list (cons 1 (list 2 3)))
=> (1 2 3)
(type *1)
=> clojure.lang.PersistentList
The easiest way would be to turn it into a vector. This data type works great in Clojure. In fact, when programming in Clojure, the most of the data is kept either in vectors or maps while lists are used for "code as data" (macro system).
In your case, the solution would be:
user=> (vec (cons 1 (list 2 3)))
[1 2 3]
I don't know such a case where you need a list exactly, not a vector or a seq. Because most of the functions operate on sequences but not strict collection types. The cons type should also work, I believe.
If you really need a list, you may use into function that is to convert collections' types. But please keep in mind that when dealing with a list, the order will be opposite:
user=> (into '() (cons 1 (list 2 3)))
(3 2 1)
So you need to reverse the input data first:
user=> (into '() (reverse (cons 1 (list 2 3))))
(1 2 3)
user=> (type (into '() (reverse (cons 1 (list 2 3)))))
clojure.lang.PersistentList
I am not understand why instead of normal list I recive (clojure.core/seq).
My code
(defn del-list [arg-list lvl] (do
(cond
(= lvl 1) (remove seq? arg-list)
:else (map #(if (seq? %)
(del-list % (- lvl 1))
%
) arg-list)
)
))
(println (del-list `(1 2 3 `(1 2 `(1 2 3) 3) 1 2 3) 2))
;result=> (1 2 3 (clojure.core/seq) 1 2 3)
Why is this happening? I don't know how valid search this, all links from google point me to documentation about seq and seq?.
Like #ClojureMostly says in the comments, don't use bacticks, use a single quote. Also don't nest them, one is enough.
So, calling your function like this:
(println (del-list '(1 2 3 (1 2 (1 2 3) 3) 1 2 3) 2))
Will solve your immediate problem.
Going into a bit more depth, there are some differencences between single quote (just called quote) and backtick (called syntax quote).
In quoting something, you say that you want just the data structure, that it shouldn't be evaluated as code. In clojure, code is data, so (+ 1 2) is a list with a symbol and two numbers which, when evaluated as code, evals to 3. So, (+ 1 2) => 3 and '(+ 1 2) => (+ 1 2).
Syntax quote is similar, but it looks up the namespaces of things and you can unquote stuff inside. This makes it useful for writing macros.
;; Looks up the namespaces of symbols to avoid the problem of variable capture
`(+ 1 2) ;=> (clojure.core/+ 1 2)
;; You can unquote parts of the expression.
;; ~ is unquote ~# is unqoute splicing
;; That should give you the vocabulary to google this.
`(+ 1 2 3 ~(* 2 2)) ;=> (clojure.core/+ 1 2 3 4)
Nested quotes are never what you want. (Unless you alternate quoting and unquoting, and even then it's usually confusing)
In clojure you'd usually represent sequential things as vectors [1 2 3] (O(n) random access, grows at the end), unless you specifically want some property of a linked list for your data. (Like representing a stack, as lists efficiently add and remove the first element.)
(defn del-list [arg-list lvl]
;; You don't need the do, there's an implicit do in many special forms
;; like let, fn and defn
;; Also you only had one thing in your do, in that case it doesn't do anything
;; There's only one condition, so I'd use if instead of cond
(if (= lvl 1)
;; And, like someone mentioned in the comments,
;; what you probably want is sequential? instead of seq?
(remove sequential? arg-list)
(map #(if (sequential? %)
(del-list % (dec lvl)) ; dec stands for decrement
%)
arg-list)))
;; This works
(println (del-list '(1 2 3 (1 2 (1 2 3) 3) 1 2 3) 2))
;; But this is more idiomatic (modulo specific reasons to prefer lists)
(println (del-list [1 2 3 [1 2 [1 2 3] 3] 1 2 3] 2))
;; If you change map to mapv, and wrap remove with vec it will return vectors
(defn del-vec [arg-vec lvl]
(if (= lvl 1)
(vec (remove sequential? arg-vec))
(mapv #(if (sequential? %)
(del-vec % (dec lvl)) ; dec stands for decrement
%)
arg-vec)))
(println (del-vec [1 2 3 [1 2 [1 2 3] 3] 1 2 3] 2))
;; But most of the time you don't care about the specific type of sequential things
As for your actual question, why does clojure.core/seq appear, I have no idea. That's not how you use quoting, so it has never come up.
I am working on some Lisp exercises using Clojure. I am trying to work these exercises without taking advantage of vectors and some Clojure functions.
This function
(defn rev-seq
[s1]
(concat (pop s1) (list (peek s1))))
puts the first element of a list at the end. I want to call this function as many times as it takes to reverse the list (without calling Clojure's reverse function).
I am not sure what to use in its place. I have experimented with map, apply, and repeat with no success. I would rather have a way to think differently about this than a straight answer, but I am not asking for a discussion.
Firstly, I think you'll need to convert rev-seq to use first/rest rather than peek/pop if you want to work on general sequences - at leas in Clojure 1.4 peek/pop seems to require a PersistentStack:
(defn rev-seq
[s1]
(concat (rest s1) (list (first s1))))
Then you should probably note that applying this function repeatedly will "cycle" a list rather than reversing it. You can see that if you look at the result of a small number of applications using iterate:
(def s '(1 2 3 4 5 6 7 8 9))
(nth (iterate rev-seq s) 3)
=> (4 5 6 7 8 9 1 2 3)
An option that would work is to reverse with a recursive function:
(defn reverse-seq [s]
(concat (reverse (next s)) (list (first s))))
(reverse-seq s)
=> (9 8 7 6 5 4 3 2 1)
Or alternatively you can do a reverse using the technique in clojure.core:
(defn reverse-seq [s]
(reduce conj () s))
(reverse-seq s)
=> (9 8 7 6 5 4 3 2 1)
Hope this gives you some ideas!
Recursion is powerful!
I translated
the solution
into Clojure.
(defn- inverte-aux
[lista resto]
(if lista
(recur (next lista) (cons (first lista) resto))
resto))
(defn inverte
[lista]
(inverte-aux lista nil))
user> (inverte [4 3 2 1 3])
(3 1 2 3 4)