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"]}

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

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

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

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

1
❀️ 1
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