clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
souenzzo 2021-02-02T02:19:48.101200Z

https://twitter.com/quoll/status/1356422446488944642 Is is an intentional or an accidental behavior?

2021-02-02T02:28:47.102Z

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

mpenet 2021-02-02T12:31:22.118200Z

: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)

mpenet 2021-02-02T12:31:30.118400Z

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

mpenet 2021-02-02T12:47:33.118600Z

aka CLJ-1676

alexmiller 2021-02-02T04:15:23.103200Z

Makes sense to me

2021-02-02T04:23:52.103400Z

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}

2021-02-02T04:24:44.103700Z

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

2021-02-02T04:25:59.103900Z

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.

2021-02-02T04:26:41.104100Z

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

2021-02-02T04:27:47.104300Z

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.

alexmiller 2021-02-02T04:47:22.104600Z

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

alexmiller 2021-02-02T04:47:53.104800Z

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

alexmiller 2021-02-02T04:49:29.105Z

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

3
πŸ‘€ 15
murtaza52 2021-02-02T08:25:39.108200Z

(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 ?

phronmophobic 2021-02-02T08:32:59.112Z

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.

phronmophobic 2021-02-02T08:34:43.113300Z

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

phronmophobic 2021-02-02T08:40:19.113800Z

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

Claudio Ferreira 2021-02-02T09:08:15.114400Z

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

murtaza52 2021-02-02T09:16:13.114700Z

thanks @smith.adriane that clears it

murtaza52 2021-02-02T09:16:48.115200Z

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

murtaza52 2021-02-02T09:20:03.116400Z

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 ?

p-himik 2021-02-02T09:40:29.116600Z

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

p-himik 2021-02-02T09:43:18.116900Z

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

πŸ‘ 1
souenzzo 2021-02-02T11:20:12.118Z

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

Wellerson 2021-02-02T14:38:17.119900Z

Can someone help me ?

Dominic Pearson 2021-02-02T15:49:56.127800Z

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) %)
                                  tables)))

(defmacro create-all-tables
  "Create database tables. Expects each table listed in the `tables` set
  to have a corresponding create-`table`-table function defined."
  [x]
  `(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);
At REPL:
enki.db> (.delete (io/file (:subname db))) (create-all-tables db) (create-data-index db)
true([0])[0]

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 (DB.java:1012).
[SQLITE_ERROR] SQL error or missing database (no such table: main.data)
Doing some macroexpand and debugging:
enki.db> (macroexpand '(create-all-tables db))
(clojure.core/map
 (fn*
  [p1__31878__31879__auto__]
  ((clojure.core/->
    (clojure.core/str "create-" p1__31878__31879__auto__ "-table")
    clojure.core/symbol
    clojure.core/resolve)
   db))
 #{"data"})

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

Dominic Pearson 2021-02-02T15:57:07.130100Z

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

enki.db> (delete-and-recreate-database)
Execution error (SQLiteException) at org.sqlite.core.DB/newSQLException (DB.java:1012).
[SQLITE_ERROR] SQL error or missing database (no such table: main.data)
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)))
true

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

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

Tomas Brejla 2021-02-02T16:00:14.130200Z

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

Tomas Brejla 2021-02-02T16:01:41.130400Z

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 Brejla 2021-02-02T16:03:17.130600Z

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

Tomas Brejla 2021-02-02T16:03:27.130800Z

@dsp ? ^^^

Dominic Pearson 2021-02-02T16:04:18.131Z

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

🀞 1
Dominic Pearson 2021-02-02T16:08:32.131300Z

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

πŸ‘ 1
2021-02-02T18:22:50.131700Z

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

2021-02-02T18:23:04.131900Z

map does a bunch of work you don't need

Dominic Pearson 2021-02-02T18:38:08.132300Z

ah perfect

2021-02-02T21:11:15.133800Z

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

dpsutton 2021-02-02T21:15:59.136900Z

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)))
"clojure.lang.LazySeq@7861"
user=>

dpsutton 2021-02-02T21:17:13.137700Z

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

p-himik 2021-02-02T21:29:19.138900Z

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

wombawomba 2021-02-02T21:33:05.139900Z

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

alexmiller 2021-02-02T21:34:04.140300Z

Java's ProcessBuilder is pretty amenable to java interop

alexmiller 2021-02-02T21:34:36.140600Z

full access to the output stream

wombawomba 2021-02-02T21:37:47.141500Z

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

wombawomba 2021-02-03T11:26:21.145700Z

@noisesmith thanks!

dpsutton 2021-02-02T21:39:10.141600Z

i always check around for things like this: https://grep.app/search?q=doto%20%28ProcessBuilder

vlaaad 2021-02-02T21:42:20.141900Z

it prints (range) forever until the end of times

vlaaad 2021-02-02T21:42:31.142100Z

and by end of times I mean and of memory

vlaaad 2021-02-02T21:42:52.142300Z

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

wombawomba 2021-02-02T21:43:03.142500Z

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

wombawomba 2021-02-02T21:43:47.142700Z

FWIW I tried to do

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

wombawomba 2021-02-02T21:45:30.143300Z

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

p-himik 2021-02-02T21:51:22.143500Z

Awesome, thanks!

wombawomba 2021-02-02T22:08:05.143900Z

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.

2021-02-02T22:40:15.144100Z

assuming the strings are the stdout of the process? you would need to use a separate thread to read that InputStream ex: https://github.com/streamsets/datacollector/blob/master/basic-lib/src/main/java/com/streamsets/pipeline/stage/executor/shell/ShellExecutor.java#L187

2021-02-02T22:40:41.144400Z

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

2021-02-02T23:22:51.144700Z

@wombawomba

user=&gt; (-&gt; (ProcessBuilder. ["ls" "-l"]) (.start) (.getInputStream) (<http://clojure.java.io/reader|clojure.java.io/reader>) (line-seq) (first))
"total 2020"

πŸŽ‰ 1
2021-02-02T23:24:36.145Z

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