Fork me on GitHub
souenzzo02:02:48 Is is an intentional or an accidental behavior?


This is intentional. When you destructure using [] you simply put symbols as variables where they belong. In your case, you've just put some weird symbols in it like :or, {c and 9}


There's no further DSL about it where you can specify things like alternate values if nil, or give a name to the whole vector


So it be more appropriate to say that its just there are less features around sequential destructuring than around associative. But there's no real "weird behavior" here, except maybe you assuming there'd be more features on offer.


Not to say this can't be a common mistake, and it be nice to know if clj-kondo can warn against this, I suspect it might already


It also bother me that they are referring to vectors as arrays 😛, Vectors are not the same as Arrays in Clojure, and the distinction matters a lot.

Alex Miller (Clojure team)04:02:22

well, neither term is right here, should be sequential destructuring

Alex Miller (Clojure team)04:02:53

or vector binding expressions (if you want to refer to the syntax)

Alex Miller (Clojure team)04:02:29

stay tuned for some new sequential destructuring features in 1.11 though ... ;)

👀 45
bananadance 9

:or is weird in a few ways, and is not intended to work inside sequential destructure


:or will also always evaluate the values you pass to it, even if not needed, it's a bit counter-intuitive if you compare with (or x y)


(let [{:or {foo (prn :foo)} :keys [foo]} {:foo :bar}]) will print :foo


aka CLJ-1676


(w/postwalk #(if (number? %) (inc %) (conj % 1)) [[1 2 3][4 5 6]])
=>[[2 3 4 1] [5 6 7 1] 1]
(w/prewalk #(if (number? %) (inc %) (conj % 1)) [[1 2 3][4 5 6]])
=>[[2 3 4 2] [5 6 7 2] 2]
trying to understand the diff between postwalk and prewalk. I understand one is postorder and the second is preorder traversal, however why do the results differ, just the traversal order is different, why should the result be different ?


consider a simpler example:

(w/prewalk #(if (number? %) (inc %) (conj % 1)) []) ;; [2]
(w/postwalk #(if (number? %) (inc %) (conj % 1)) []) ;; [1]
prewalk will visit the vector and conj, followed by inc ing the number just added postwalk will try to visit the children of the vector (it doesn't have any), then it will visit the vector which conj's the 1.


basically, prewalk will visit the parent node and visit the children of the node after the parent has been modified. postwalk will visit children before parents and the parent will have the modified children when the parent is visited


(defn visit [x]
  (println x)
(w/prewalk visit [1]) ;; [1]
;; prints
;; [1]
;; 1
(w/postwalk visit [1]) ;; [1]
;; prints
;; 1
;; [1]

Claudio Ferreira09:02:15

Tell me a project where i can show my cloj habilities to a HR recruiter.


thanks @smith.adriane that clears it


I guess u should add your example to clojuredocs .... it will be helpful to others too


Check out clojure.walk/postwalk-demo and clojure.walk/prewalk-demo.


what is a practical application of postwalk/prewalk ? any real world examples of where it is more convenient to use prewalk/postwalk rather than clojure.core fns ?


In one of the projects, I generate with it a nested table of contents for a Hiccup-based web page.

👍 3

I used walk a bit for handle "unknow data sources", but now i use #specter


Can someone help me ?


I have a really weird issue. I don't understand what is happening. I'm using hugsql and sqlite. I've cut this down to a smaller snippet I can reproduce the strange behaviour with while also providing some context:

(def db {:classname "org.sqlite.JDBC"
         :subprotocol "sqlite"
         :subname (str (System/getProperty "user.home") "/.enki.db")})

(def tables #{"data"})

(def tables-loaded (into #{} (map #(let [p (str "enki/db/sql/" % ".sql")]
                                     (hugsql/def-db-fns p) %)

(defmacro create-all-tables
  "Create database tables. Expects each table listed in the `tables` set
  to have a corresponding create-`table`-table function defined."
  `(map #((-> (str "create-" % "-table") symbol resolve) ~x) ~tables))
In sql/data.sql I have the following barebones hugsql def:
-- :name create-data-table
-- :command :execute
-- :result :raw
-- :doc Create data table
create table data (hash string, data blob);

-- :name create-data-index
-- :command :execute
-- :result :raw
-- :doc Create data index
create index index_hash on data(hash);
enki.db> (.delete (io/file (:subname db))) (create-all-tables db) (create-data-index db)

enki.db> (do 
           (.delete (io/file (:subname db)))
           (create-all-tables db)
           (create-data-index db))
Execution error (SQLiteException) at org.sqlite.core.DB/newSQLException (
[SQLITE_ERROR] SQL error or missing database (no such table:
Doing some macroexpand and debugging:
enki.db> (macroexpand '(create-all-tables db))
    (clojure.core/str "create-" p1__31878__31879__auto__ "-table")

enki.db> (map #(-> (str "create-" % "-table") symbol resolve) tables)


Something really weird is going on. Defining a fn at the REPL, with three should-be-independent actions:

enki.db> (defn delete-and-recreate-database []

           (let [database-file (io/file (:subname db))]
             (when (.exists database-file)
               (.delete database-file)))

           (let [x (create-all-tables db)] x)

           (create-data-index db))

enki.db> (delete-and-recreate-database)
Execution error (SQLiteException) at org.sqlite.core.DB/newSQLException (
[SQLITE_ERROR] SQL error or missing database (no such table:
When executed one by one, not in a funcall:
enki.db> (let [database-file (io/file (:subname db))]
           (when (.exists database-file)
             (.delete database-file)))

enki.db> (let [x (create-all-tables db)] x)

enki.db> (create-data-index db)
Really scratching my head. 😞

Tomas Brejla16:02:14

don't you have to use a doall around the map in create-all-tables ?

Tomas Brejla16:02:41

I just quickly skimmed through your code and it seems that create-all-tables will ouput a lazy sequence you don't touch in any way.. therefore it effectively has no need to actually execute the code you feed into map function.

Tomas Brejla16:02:17

of cource if you used this form in repl:

(let [x (create-all-tables db)] x)
..then it actually had to execute the code behind lazy sequence, as repl itself is trying to print the content of lazy sequence, which forces the code to be executed


Ah, bitten by laziness again. This makes sense. I'll see if I can force it! Thanks!

🤞 3

That indeed was exactly the problem. Wrapping with doall solved my issue. Thank you so much.

👍 3

you can replace (doall (map f coll)) with (run! f coll) if you don't use the return value and there's just one collection arg


map does a bunch of work you don't need


ah perfect


This such a common issue, I wonder if it be beneficial to have nRepl not walk lazySeq to print them. So when a lazy-seq is returned to the REPL, it wouldn't realise it, which would make people realize they arn't doing it right


that would make the "P" in REPL pretty weak with how Clojure is implemented. and it would be more like the far more annoying str on a lazy seq:

/p/clojure ❯❯❯ clj
Clojure 1.10.2
user=> (map inc (range 3))
(1 2 3)
user=> (str (map inc (range 3)))


imagine the second form there was just (map inc (range 3)) and you got back "() ;; because you haven't forced evaluation"


@vlaaad reveal doesn't have anything to prompt a user about attempting to print a potentially infinite lazy seq, does it?


it prints (range) forever until the end of times


and by end of times I mean and of memory


I have respecting *print-length* on my todo-list...


Awesome, thanks!


So I need to run a shell process and handle its output asynchronously line-by-line. What's the easiest way to do this?

Alex Miller (Clojure team)21:02:04

Java's ProcessBuilder is pretty amenable to java interop

Alex Miller (Clojure team)21:02:36

full access to the output stream


Any pointers on how I'd use ProcessBuilder to get a lazy seq or similar of strings? My Java is a bit rusty 😅


i always check around for things like this:


Thanks.. although I'm not finding any good examples of what I'm trying to do there


FWIW I tried to do

(first (line-seq ( ( (.getErrorStream (.start (java.lang.ProcessBuilder ...))))))
but it doesn't seem to produce any output until the process exits


(and when the process does exit, it gives me an error)


Alright, I found another way to do what I wanted to accomplish 🙂 Will keep ProcessBuilder in mind for next time I want to do something like this.

Jeff Evans22:02:15

assuming the strings are the stdout of the process? you would need to use a separate thread to read that InputStream ex:

Jeff Evans22:02:41

(a bit confusingly, the process stdout is actually an InputStream from the POV of the Java code, and it’s obtained via getInputStream()



user=> (-> (ProcessBuilder. ["ls" "-l"]) (.start) (.getInputStream) () (line-seq) (first))
"total 2020"

🎉 3

it was likely waiting on the stdout being consumed while you were waiting for data on stderr