clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
Nom Nom Mousse 2021-06-01T08:12:10.234100Z

One returns a list, the other a string. I want both to return a string. How do I fix this?

user=> (apply merge-with (fn [& args] (str/join " " (flatten args))) '({0 ["abc"]} {0 ["def"]}))
{0 "abc def"}
user=> (apply merge-with (fn [& args] (str/join " " (flatten args))) '({0 ["abc"]}))
{0 ["abc"]}

Nicolas Estrada 2021-06-01T08:18:34.234200Z

@seancorfield I heard through the grapevine that you are the one maintaing tools.cli? Any thoughts?

Nom Nom Mousse 2021-06-01T08:19:19.234400Z

I guess Lisps are always going to be something for the initiated. It would be interesting to see Clojure compared to other Lisps in such a graph.

Nom Nom Mousse 2021-06-01T08:22:43.235400Z

(into {}
        (for [[k vs]
              (apply merge-with concat <list>)]
           [k (str/join " " vs)]))

thheller 2021-06-01T08:27:25.236200Z

I'd probably make the merge or even group-by and then as a separate step join the strings (eg. clojure.walk or just reduce)

Nom Nom Mousse 2021-06-01T09:00:58.238100Z

walk I hadn't heard of. Seems cool, but feels kinda un-clojuric: "do this then that" in one function.

2021-06-02T18:36:55.290200Z

walk isn't "do this then that", it's "apply this transformation to each level of a nested structure", which is very "clojuric"

Nom Nom Mousse 2021-06-03T14:03:40.332200Z

But you have one transformation you do at each level and then you have one you do at the end on the result, right?

(walk #(* 2 %) #(apply + %) [1 2 3 4 5])
This seems less complected to me:
(apply + (walk #(* 2 %) [1 2 3 4 5])

2021-06-03T14:08:59.332700Z

walk itself is rarely needed - it's a building block for implementing post-walk and pre-walk, and more elegant than the two being mostly copy/paste of one another

1👍
Christoffer Ekeroth 2021-06-01T09:02:26.238200Z

@endrebak

1😎
Christoffer Ekeroth 2021-06-01T09:02:39.238400Z

You can make your own at https://trends.google.com/

magra 2021-06-01T09:25:26.238700Z

Since I have seen you in the cider channel, there is clojure-convert-collection-to-vector, normally bound to C-c C-r [

Ed 2021-06-01T09:27:13.238900Z

there's this too : https://github.com/Datomic/codeq ... which I've never played with enough to have anything substantial to say about it .... but it's interesting

Nom Nom Mousse 2021-06-01T09:44:31.239300Z

Thanks!

magra 2021-06-01T09:45:55.239500Z

I still say "I google" but i do not use google anymore but alternative search engines. I also block analytics, third-party cookies etc. And all the (not)"googling" I do for clojure rarely includes the word clojure as a search term. When I go to clojure cheatsheet, clojure toolbox or clojureverse they open from my browsers history. Then libraries in clojure have names which don't give away what the do, so (not)"googling" for "fulcro" "luminus" "reagent" will rarely include the search term "clojure". Even "clj-pdf" or "clj-http" will not show up as the searchterm clojure.

magra 2021-06-01T09:49:15.239700Z

As an aside: The red-monk, or whatever, popularity of programming languages index only uses searches, I suspect google only, for "x programming language". Now, who would ever google "clojure programming language"? In real life you google "java" then find out the search was to wide and then try again googling "java programming language". With clojure you google "clojure" and you got it. No need to ever refine the search.

Nom Nom Mousse 2021-06-01T10:17:41.241700Z

I'm trying the Clojure tools.cli https://github.com/clojure/tools.cli#quick-start in the REPL and am getting these errors:

my.program> (parse-opts {:port 80} cli-options)
Execution error (ClassCastException) at clojure.tools.cli/tokenize-args (cli.cljc:34).
class clojure.lang.MapEntry cannot be cast to class java.lang.CharSequence (clojure.lang.MapEntry is in unnamed module of loader 'app'; java.lang.CharSequence is in module java.base of loader 'bootstrap')
my.program=> (parse-opts "{:port 80}" cli-options)
Execution error (ClassCastException) at clojure.tools.cli/tokenize-args (cli.cljc:34).
class java.lang.Character cannot be cast to class java.lang.CharSequence (java.lang.Character and java.lang.CharSequence are in module java.base of loader 'bootstrap')
What is the correct usage from the REPL?

borkdude 2021-06-01T10:21:10.242200Z

@endrebak

(parse-opts ["-p" "2020"] [["-p" "--port PORT" "Port number"]])

borkdude 2021-06-01T10:23:07.242700Z

$ bb -e '(clojure.tools.cli/parse-opts ["-p" "2020"] [["-p" "--port PORT" "Port number"]])'
{:options {:port "2020"}, :arguments [], :summary "  -p, --port PORT  Port number", :errors nil}

Nom Nom Mousse 2021-06-01T10:23:44.242900Z

Wonderful!

Nom Nom Mousse 2021-06-01T10:25:00.243400Z

To use it my way I'll do:

(defn -main [& args]
  (let [opts (if (map? (first args))
               (first args)
               (parse-opts args cli-options))]
    (start-app opts)))

borkdude 2021-06-01T10:31:11.244Z

It's probably better to write another function, since by convention -main functions receive string args

simongray 2021-06-01T10:32:38.244100Z

@endrebak (for [[a b _ d] ls] [a b d])

simongray 2021-06-01T10:32:48.244300Z

just use destructuring if you want it shorter

Nom Nom Mousse 2021-06-01T10:35:04.244500Z

True! With a name like start-from-repl or start-with-map or something.

Nom Nom Mousse 2021-06-01T10:36:00.244700Z

That is a good suggestion! Since I am parsing java exceptions I think I can be sure each row has four elements.

roklenarcic 2021-06-01T11:59:21.246500Z

I have a callback function and it might use some of the dynamic bindings, which are not the same when the callback is called as when it was created. I was trying to solve it by using clojure.core/binding-conveyor-fn but that thing is private. What’s the best solution for this (capturing bindings when making a function)?

flowthing 2021-06-01T12:01:27.246600Z

https://clojuredocs.org/search?q=bound-fn

2021-06-01T12:03:35.246800Z

you could simply use let

(def ^:dynamic *foo* 1)

(def ^:dynamic *bar* 2)

(def f
  (let [foo *foo*
        bar *bar*]
    (fn []
      (+ foo bar))))

(binding [*foo* 2 *bar* 5]
  (f)) ;; => 3 not 7

Nom Nom Mousse 2021-06-01T12:12:56.248300Z

Are there strings containing command line commands that might break because I have to split them?

(clojure.java.shell/sh "echo hi") ;; fails
(clojure.java.shell/sh (clojure.string/split "echo 'hi there'" #" ")) ;; works in this case, but will it do so for all?

borkdude 2021-06-01T12:16:25.249Z

@endrebak babashka.process has a function called tokenize will will split shell strings for you

borkdude 2021-06-01T12:20:44.249300Z

Since you also asked in #babashka I gave more info there

Nom Nom Mousse 2021-06-01T12:34:25.249400Z

Thanks! I meant to delete some of the qs that weren't specific to bb, but I must have forgotten. Thanks again!

roklenarcic 2021-06-01T12:45:16.249700Z

thank you so much flowthing

Nom Nom Mousse 2021-06-01T13:12:58.250300Z

What am I doing wrong here?

user> (require '[clojure.java.shell :refer [sh]])
user> (sh "bash" "-c" "sleep" "1" ";" "echo" "hi")
;; => {:exit 1, :out "", :err "usage: sleep seconds\n"}

2021-06-01T13:15:00.250400Z

bash -c expect a string this should work (sh "bash" "-c" "sleep 1")

Linus Ericsson 2021-06-01T13:15:11.250600Z

yes (sh "bash" "-c" "sleep 1; echo hi")

Nom Nom Mousse 2021-06-01T13:15:20.250800Z

Yes! That actually made it a lot easier too 🙂 Thanks

Nom Nom Mousse 2021-06-01T13:16:39.251600Z

How can I dispatch a shell/sh job and then be notified when it is finished?

2021-06-02T18:38:05.290400Z

also, ProcessBuilder / Process are not very hard to use, and support a lot of thinks shell/sh doesn't do

2021-06-02T18:40:40.290600Z

for example this runs lua and sends to its stdin after it starts:

let [pb (ProcessBuilder. ["lua"])
      p (.start pb)
      out (.getOutputStream p)
      in (.getInputStream p)]
  (spit out "print \"hello from lua\"\n")
  (slurp in))
returns the string "hello from lua\n" if you have lua installed

1❤️
Nom Nom Mousse 2021-06-03T14:00:34.332Z

Thanks! I'll remember that if I ever need more advanced functionality 🙂

Nom Nom Mousse 2021-06-01T13:18:54.251700Z

This seems like one way: https://stackoverflow.com/questions/16349415/is-there-a-way-to-be-notified-when-a-clojure-future-finishes Would love to hear better suggestions 🙂

Nom Nom Mousse 2021-06-01T13:19:43.252Z

Jeez, that was simple:

(future (computation) (callback))

11❤️
seancorfield 2021-06-01T15:30:43.252600Z

Look in the tools.cli category on http://ask.clojure.org — there have been discussions about this recently.

kwladyka 2021-06-01T16:31:11.253100Z

> (Also worth remembering is that if Google Trends is a valid quality metric we should all be coding in Java / JavaScript 😉) Not really. Java doped too. Bur Rust is going up.

kwladyka 2021-06-01T16:34:10.253300Z

BTW What do you use to block cookies? Do you block all of them in web browser or user adblocker?

Rina 2021-06-01T21:55:44.258700Z

Hi, I have a vector of keys and a value. How can I create a map where the vector turned into nested keys and the value is the value of those keys? For example: This is the vector

[:a :b :c]
And this is the value:
{:name "John"}
I want the result to be:
{:a {:b {:c {:name "John"}}}}
Thanks

borkdude 2021-06-01T21:56:45.259300Z

@rinam (assoc-in {} the-vector the-map)

Rina 2021-06-01T21:57:11.259900Z

@borkdude Thank you!

dpsutton 2021-06-01T23:45:57.260900Z

is there some magic config to help CircliCI understand test.check failures a bit better?

(defspec oops
  (prop/for-all [x gen/int]
    (even? x)))
And the output is

dpsutton 2021-06-01T23:46:52.261400Z

I can get the output out of the "STEPS" tab, but would be nice if it was present in the "TESTS" report tab