beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Joel Jucá 2021-05-20T00:07:56.125Z

@rob370 did you check Exercism already? It’s both a community and command-line app that provides a learning experience along with a community-powered mentorship program

Joel Jucá 2021-05-20T00:08:00.125200Z

http://exercism.io

2021-05-20T00:09:44.125500Z

Oooh @joelwallis good recommendation

✌️ 1
Joel Jucá 2021-05-20T00:12:22.127800Z

Exercism is awesome! I’ve even contributed to the JavaScript and the [now dead] ECMAScript track in the past. It’s really a master piece of self-learning platforms. I’ve been on it for JS, Elixir, Erlang, Python, Ruby, and other languages. Lots of fun is mostly guaranteed! 😆

pithyless 2021-05-20T07:07:09.131500Z

@joelwallis there is an #exercism channel where people contributing to the Clojure track hang out

👍 2
Joel Jucá 2021-05-20T12:08:50.132200Z

Awesome!!!

2021-05-20T01:33:33.128600Z

How can I make this code return strings rather than individual characters?

2021-05-20T13:47:21.132600Z

(let [car-names ["audi" "bmw" "fiat" "haval"]
      car-models ["" ["x1" "i3"] "500" ""]]
  (->> (map (fn [car-name car-model]
              (cond
                (= "" car-model) [car-name]
                (coll? car-model) (map (fn [model] [car-name model]) car-model)
                :else [car-name car-model]))
            car-names car-models)
       flatten))
;; => ("audi" "bmw" "x1" "bmw" "i3" "fiat" "500" "haval")

Ivan Koz 2021-05-20T14:11:34.132800Z

map would fit better for that case

(def cars {"Audi" []
           "BMW" ["X1" "i3"]
           "Fiat" ["500"]
           "Haval" []})
           
=> #'user/cars
(for [brand (keys cars) 
      model (or (seq (cars brand)) [""])]
  (str brand (when (seq model) " ") model))
=> ("Audi" "BMW X1" "BMW i3" "Fiat 500" "Haval")

2021-05-20T15:36:22.135300Z

alternative to looking up the keys is grabbiing keys and vals together:

(for [[brand models] cars
      model (or (seq models) [nil])
      :let [model-str (if model
                          (str " " model)
                          "")]]
   (str brand model-str))
(also used let in an attempt to aid readability)

2021-05-20T01:42:53.128700Z

what should the output look like?

2021-05-20T01:43:54.128900Z

is this right?

(let [car-names ["audi" "bmw" "fiat" "haval"]
      car-models ["" ["x1" "i3"] "500" ""]]
  (map vector car-names car-models))
;; => (["audi" ""] ["bmw" ["x1" "i3"]] ["fiat" "500"] ["haval" ""])

2021-05-20T01:46:13.129100Z

but i would adjust car-models to be [[] ["x1" "i3"] ["500"] []], if possible

2021-05-20T01:46:32.129300Z

which gets you

(let [car-names ["audi" "bmw" "fiat" "haval"]
      car-models [[] ["x1" "i3"] ["500"] []]] ;; empty list instead of empty string
  (map vector car-names car-models))
;; => (["audi" []] ["bmw" ["x1" "i3"]] ["fiat" ["500"]] ["haval" []])

2021-05-20T01:46:58.129500Z

or even

(let [car-names ["audi" "bmw" "fiat" "haval"]
      car-models [[] ["x1" "i3"] ["500"] []]] ;; empty list instead of empty string
  (->> (map vector car-names car-models)
       (into {})))
;; => {"audi" [], "bmw" ["x1" "i3"], "fiat" ["500"], "haval" []}

2021-05-20T02:05:24.129800Z

This is the desired output ; desired output of the function = “Audi, BMW X1, BMW i3, Fiat 500, Haval”

2021-05-20T02:06:46.130Z

I’m going to try the empty lists

Jacob Rosenzweig 2021-05-20T03:18:56.130500Z

Is a threading macro basically equivalent to ocaml piping?

sova-soars-the-sora 2021-05-20T14:40:59.133900Z

Yes I think so. Note that Clojure has thread-first -> and thread-thru ->>

2021-05-20T15:42:09.135500Z

@rosenjcb the important difference is that OCaml piping is semantic, and clojure threading macros (as all macros) are syntactic - a pipe creates a series of applications, a threading macro does a code rewrite to be more concrete, OCaml piping can't do this:

user=> (->> (+ a b) (let [a 23 b 19]))
42
it also doesn't have this commonly seen newb trap error:
user=> (macroexpand '(-> y (fn [x] (+ x x))))
(fn* y ([x] (+ x x)))

2021-05-20T15:43:59.136700Z

lists of symbols that are not yet compiled is a lower level, more flexible, and more error prone domain compared to the operatioins the pipes do the macro rearranges symbols in lists, the pipe operator does higher order application and value capture

2021-05-20T15:46:45.139800Z

I think it's good style to use the clojure threading macros as if they were semantic, but you can't really use them fluently without understanding they are syntactic

Luciano Laratelli 2021-05-20T03:25:01.131Z

hi! is this the appropriate channel for newbie cljs questions, or should that be in #clojurescript? 🙂

dpsutton 2021-05-20T03:26:38.131200Z

Here’s fine.

Luciano Laratelli 2021-05-20T03:26:53.131300Z

Thanks!

valerauko 2021-05-20T15:10:36.135100Z

anyone knows if doing the tonsky-way formatting in atom is possible? (https://tonsky.me/blog/clojurefmt/ ) i tried tweaking the paredit plugin's regex but no luck...

Juλian (he/him) 2021-05-21T09:42:29.172600Z

Off topic: That site has an awesome dark mode!

👍 1
MikeE 2021-05-20T15:49:13.142400Z

hello! i have a question regarding structuring a part of an application I’m working on. It may not actually be a beginner question but Clojure is new to me so feel free to point me to another channel 🙂 I’m developing a REST API and have a need to run a worker process/thread long polling SQS for messages continuously and I wasn’t sure where to put something like that in my codebase nor how to kick off the process so it’s not blocking anything. Is there any code samples possibly or ideas on how to structure this and what part of the stdlib may help with this. FWIW I’m starting project this as a monolith. I have a lot of experience with building micro services but this is a solo project and micro services don’t feel appropriate at this stage of development.

MikeE 2021-05-20T15:50:16.143300Z

Also if this question is too complex to answer in Slack I’m happy to post on clojureverse

2021-05-20T15:52:59.145Z

@mike741 the answer that's usually good enough for your first draft is to use future , which propagates bindings for dynamic vars, starts your code in a new thread (in an expandable thread pool) and returns a handle you can use to check exit or error status, or even cancel it if it calls cancellable methods like Thread/sleep periodically.

Darin Douglass 2021-05-20T15:53:59.145700Z

^ in general it depends on what you're wanting to do, but that suggestion is a good starting point

2021-05-20T15:54:53.146Z

user=> (def f (future (loop [] (println "looping") (Thread/sleep 1000) (recur))))
#'user/f
user=> looping
looping
looping
looping
looping
looping
looping
looping
looping
looping
(future-cancel f)
true

2021-05-20T15:55:24.146500Z

the threading mixes up the program output and my input here, but it shouldn't be too hard to figure out

2021-05-20T15:57:17.148300Z

do note that future-cancel is opt in - you need to call something that respects that it should abort if the current thread is cancelled (the jvm has code that isn't cancellation safe, so the method that actually no questions asked kills a thread isn't safe to use)

MikeE 2021-05-20T16:46:10.149Z

ok cool thank you for that pointer.. that seems pretty straightforward.. I’ll check that out.. Much appreciated!

2021-05-20T17:00:36.149800Z

for more advanced usages there are libraries like claypoole or the built in java executor service

valerauko 2021-05-20T17:05:12.150100Z

personally i find manifold very easy to use

👍 1
MikeE 2021-05-20T17:50:45.151500Z

my use case is pretty simple.. poll SQS for messages, on receipt of message(s) loop through them and do a database update.

MikeE 2021-05-20T17:52:34.153500Z

I just wasn’t sure which part of the stdlib I should start with to get a thread running out to the side continuously in order to support polling the queue. thanks again all!

piyer 2021-05-20T20:27:43.155200Z

How do I turn on the sql debugging with seancorfield/next-jdbc ?

seancorfield 2021-05-20T21:04:32.155600Z

@munichlinux What do you mean by “sql debugging”?

piyer 2021-05-20T21:53:00.155700Z

I am trying to log the sql statements.

seancorfield 2021-05-20T23:16:38.155900Z

There’s currently nothing built into the library for that. For execute! and execute-one! you could write a wrapper that logged the sql-params vector.

seancorfield 2021-05-20T23:18:01.156100Z

In theory you could write something like next.jdbc.default-options that lets you wrap a connectable in something that would log the sql-params prior to calling the implementation.

seancorfield 2021-05-20T23:21:23.156300Z

There are some interesting edge cases: what should you do for a prepare call? It doesn’t actually run the query, it just builds a PreparedStatement, and in general you can’t get the actual SQL back out of those in a generic JDBC way. What about plan which doesn’t do anything until it is reduced? What about sensitive data being passed in as parameters?

seancorfield 2021-05-20T23:22:36.156500Z

Logging result sets is even more fraught since they can be arbitrarily large — and for plan they are not really exposed since the whole point is to reduce over the ResultSet, iterating across it without even producing Clojure data structures.