Fork me on GitHub
Michael Agres00:04:09

I have to admit, I'm struggling with understanding these early programming problems. If anyone else has gone through the Brave and True book (this is from Ch4), what was your reading experience like? And did how did you find the exercises in these early chapters? > Write a function, 'validate', which will check that :name and glitter-index are present when you append. The function should accept two arguments: a map of keywords to validating functions, similar to conversions, and the record to be validated. > > ;; is this the proper setup? > > (defn validate > {:name identity > :glitter-index str->int} ;; this is the argument in a conversions function in this chapter. > [record] > ;; 1. how do I map something like ["John Smith" "0"] into its different parts? Is (map #(clojure.string/split " ") appropriate here? > ;; 2. and then how do I validate that something like ["John Smith" "0" "$%^"] won't work? > ;; 3. do I use println() to output an error message? > ;; 4. what's the proper way to call this function? > ;; 5. if I call it within append, do I wrap it within my (conj) function call? > )


You can pull apart a hash map in two different ways: you can either call keys to get a sequence of the keys (in some unspecified order) and then walk that sequence, looking up values from the original map by each key, and calling the validation function for that key, if any was given; or you can use reduce-kv to walk keys and values at the same time.


Your validate function should take two arguments -- you only have one (the record). I'm not familiar with the exercises in the book so I don't know what it is actually asking you to produce -- a result that indicates whether or not the record is valid?


(defn validate [valid-fns record] ..)


Ah, just looked up that chapter online... the exercises don't give much detail 😞 There are several possible solutions I guess... you could throw an exception for the first invalid key (but I don't think exceptions have been covered at that point?), or perhaps return a vector of validation errors (and the caller could decide what to do (if (seq errors) (handle-bad-record errors) (append-the-valid record)) kind of thing).


Part of the complication (for me, reading this) is that the book has only introduced some very basic core functions so the way I would typically write the code would use core functions the book hasn't covered... mapify is quite a bit more complex than it needs to be, because I think it was written for an early version of Clojure and more powerful core functions have been added since then?


Hopefully, you'll also get responses from folks who've gone through Brave more recently as their introduction to Clojure and can elaborate on how they interpreted those exercises...


(I find it weird that conversions is defined as a global and then convert takes just key and value and looks the key up in the global, but the exercise for validate expects you to pass the map of key validation functions in as an argument)


Maybe @U0AQ1R7FG himself can chime in when he's awake/at his desk tomorrow?


Sorry that it’s confusing! I don’t remember what my original intention was but I believe I meant for the exercises to be somewhat loose to encourage you to try things out and see what works for you. I think in some cases I suggest doing things in ways that (hopefully) illuminate what’s possible with clojure / functional programming


@U0AQ1R7FG I think the most FP solution here would be to return a sequence of zero or more validation errors?


yeah that sounds right to me


What version of Clojure was this originally written against? I can't remember how old the book is...


and you’re right that mapify is more complex than it needs to be 🙂 i think it was published almost 7 years ago? also I was still learning Clojure as I wrote it 😅


If I ever revisit there’s a lot I’d like to do to make it clearer and ease the learning curve


@U037SG1L9PV perhaps one way to get unstuck would be to write a validate function however you want to?

Michael Agres22:04:06

So then my definition becomes (defn validate [map-of-keywords record]) @U0AQ1R7FG Thanks for the reply. I think I planned out what I want the function to do. But I struggle with applying what I think I've learned in the chapter to write code for it. I'm stuck in that beginner phase in which I'm looking for an exact like-for-like solution to create. Can you please offer any advice to approach these problems that promotes learning and minimizes frustration/headaches/feeling dumb?


@U037SG1L9PV what's your prior programming experience? Depending on what you already know, we might be able to give you better pointers...


(in general, if your background is imperative/oop, then learning your first FP language is inherently hard because most of what you're used to "doesn't exist" -- no assignment, no iteration/loops based on mutable variables, no side effects in most FP code)

Michael Agres23:04:02

@U04V70XH6 Let's say it's less than that. I'm one of those programming language dabblers. I'm the type who took a few programming classes in college -- Visual Basic and Java. These days, I looks at code semi-regularly during the 9-5 (I do a lot of declarative stuff in Salesforce) -- but only looking up references to Apex classes in Lightning components (developers code). I'm the type who starts > stops > starts learning programming independently, and jumps around to different languages without finding something that sticks (i.e. - when it breaks me -- and it's been almost immediate with trying to learn Clojure). I did build a small app in C# once, but that’s way behind me now. So I still come in with very little experience.


Fair enough. You may do better with someone guiding you directly, such as a workshop, than self-directed learning from a book in that case. I was involved with ClojureBridge a lot at the beginning and it was aimed at taking complete beginners and walking them through enough basics with Clojure to be able to write and understand simple programs -- but it was pretty hands-on and some people certainly did struggle.

Michael Agres00:04:10

I've looked at ClojureBridge; they don't have any upcoming events.


It was created to get more women into Clojure but the pandemic has meant no in-person events for quite a while.


Some 'bridge workshops accept men as a +1 to a woman attendee but not all. The concept came from the Ruby/Rails community (RailsBridge).

Michael Agres00:04:47

Where else can I go, besides asking very fundamental questions here?

Michael Agres00:04:11

(Assuming I'm asking the right questions)


This channel is probably going to be your best bet for friendly, patient help, from folks who've opted-in to helping beginners. And your questions are just fine -- there's nothing wrong with struggling as you first get started with a completely new paradigm and language.

Michael Agres00:04:57

Sounds re-assuring. Right now, all I know how to do in Clojure is start a REPL in VS Code (h/t Calva), some arithmetic, and that the str function doesn't need any commas between arguments.


Do you have the book Getting Clojure (by Russ Olsen)? A lot of people recommend that for beginners. Totally understand if you're trying to stick to free online stuff for now. Do you like video tutorials, or do you prefer books?


Another free site to look at, if you haven't already: -- I think that's got some fairly gentle introductory material as well.

Michael Agres00:04:20

Do people really recommend that for beginner beginners? Pragmatic Programmers says it's geared more towards intermediate/experts. I have physical copy of Brave and True. I tried a video tutorial once with Javascript, but it didn't resonate. From what I can gather based on my regular 9-5, I learn best kinesthetically and from material that's accessible.


Re: Getting Clojure -- I think the pragprog site has it miscategorized. I see a lot of folks here recommend it to beginners although in the preface it does say "This book is for people with some programming experience—perhaps in Java or JavaScript or Ruby or Python—who want to learn Clojure."


(I think most entry-level Clojure books say something very similar)

Michael Agres00:04:54

I'll consider the book, thanks.


Programming Clojure, another book often recommended to beginners, says "As such, this book is for programmers with experience in a programming language like Java, C#, Python, or Ruby, but new to Clojure and looking for a powerful, elegant language." -- so I'd consider Getting Clojure to be aimed as a more beginner market than Programming Clojure.


Living Clojure, on the other hand, seems to be aimed at somewhat experienced programmers who want to learn Clojure, based on its preface notes. (I have pretty much every Clojure book, several in multiple editions, so I can generally pull them up and check on their intended audience fairly easily).

Michael Agres23:05:27

What about Joy of Clojure?


Joy of Clojure is a great book for the "why" of Clojure but it's generally not recommended to beginners.

Michael Agres00:05:35

Got it, thanks. What about anything LISP-related, such as The Structure and Interpretation of Computer Programs?


SICP is a pretty academic book, as I recall, and it's old... but it is a classic and might be worth reading just for itself (but it won't help you with Clojure because SICP assumes Lisp with mutable variables).


Asking here too as Polylith group seems inactive a bit In Polylith real world example here: How does env pick the env.edn file from root level in this file? I'm running repl for my own project and components treat it's own folder as root level, not workspace root.


You need to be a bit more patient. It's late at night West Coast USA and it's very early in Europe so very few Polylith users are awake right now. It's best not to cross-post questions unless no one has answered in 24 hours.

👍 1
❤️ 1

That's the file he linked to in his question.


I answered in #polylith


It really has nothing to do with polylith, the code loads env.edn from the current working directory wherever you start the jvm


See my answer in the thread in #polylith 🙂


(and remember you're in #beginners here, not #clojure 🙂 )


I'm trying to create a build, but end up getting this exception. How can I figure out where it's coming from? There are no references to my own code in the trace.


Actually, I guess there is this line referring to my own code: > at clojure.core.server$loading__6737__auto____8865.invoke(server.clj:9) Hmm, line 9 there is just the defstate:

(defstate http-server
  (let [cfg     (get config :org.httpkit.server/config)
        stop-fn (run-server middleware cfg)]
    (log/info "Starting webserver with config " cfg)
    {:stop stop-fn})
  (let [{:keys [stop]} http-server]
    (when stop

(defn -main [& args]
  (mount/start-with-args {:config "config/prod.edn"}))

Alex Miller (Clojure team)11:04:25

It looks like a spec is malformed from the error. Do you have specs on anything here?


@U064X3EF3 I don't believe so. Not my own definitions, at least. Is there some way to get it to tell me which spec is malformed?

Alex Miller (Clojure team)12:04:16

How are you running your app to get the exception?

Alex Miller (Clojure team)12:04:07

You could try -Dclojure.spec.skip-macros=true

Alex Miller (Clojure team)12:04:48

But that's just bypassing the check that's failing, but might allow loading enough stuff to figure it out


In this case I'm building with clojure -M:shadow-cli:xtdb release :main.

Alex Miller (Clojure team)12:04:48

Something is amiss, but it is hard for me to tell what


Okay, thanks for looking @U064X3EF3. I'll keep poking around and I'm sure will eventually find it.


Is it possible one of the dependencies is AOT-compiled with a different version of Spec to what the version of Clojure expects? The line you highlighted is from clojure.core.server, not your server.clj file.


@U04V70XH6 I'm not sure how I'd figure that out. I fiddled around with it, couldn't figure it out. Got some help and still couldn't get to the bottom of it. Ultimately ended up deleting my ~/.m2 and after that things just worked :man-shrugging:

quan xing11:04:23

In next.jdbc query sql How to use dynamic columns in sql :

(defn q [columns id]
   (jdbc-sql/query con ["select ? from  unit where id=?"  columns id]))
call this function : (q ds "id,name" 1) output sql : next.jdbc/execute! [select ? from bz_unit where id=? 1 id,name] nothing return


Column names cannot be parameters in JDBC. Take a look at HoneySQL to build your vector of SQL + params. Then you can do:

(defn q [columns id]
  (jdbc-sql/query con (h-sql/format {:select columns :from :unit :where [:= :id id]})))
and HoneySQL will build the SQL string and lift id's value out as a parameter for you. It can also quote column and table names correctly for your database.


Also, questions about SQL stuff are more likely to be answered in #sql (or #honeysql if you have Qs about that). Questions about specific libraries can get "lost" in #beginners because it is fairly high-traffic.

Ian Fernandez14:04:59

How can I trigger some function that is inside a shutdownHook in the runtime without closing the repl?


you can call (System/exit 0) but that will kill your repl because during development your repl is your running application

Ian Fernandez14:04:36

I was thinking about adding a sighandler for repl

Ian Fernandez14:04:44

but I don't know how to do it


you can intercept calls to shutdown with the security manager, but oh god why>


you can also just have the shutdown function be also in a var you can just call

Ian Fernandez17:04:44

how can I do this stuff with the security manager?

Ian Fernandez17:04:43

yeah, I'm trying to see if some code inside a shutdownHook is running or finishing to run etc. that stuff is something that I debugging in a legacy system


> is running or finishing to run etc. I don't think the JVM actually makes any guarentees about this


and this code will stop working very shortly in the scope of things

Ian Fernandez17:04:05

not the best way huh

Ian Fernandez17:04:40

seems ike I'll need to reinvent some wheels because the wheels that had been built here were ugly and strange


can you describe what is happening/what you need to verify in more specificity?

Ian Fernandez17:04:02

some code inside a shutdownHook is not working at it should, someone had a good idea to describe the "system graceful-shutdown" inside shutdown-hooks that take a value from a core.async channel when it runs

Ian Fernandez17:04:58

I'm just trying to see if the code that take the thing from the channel actually runs

Ian Fernandez17:04:17

yeah, this stuff is hella crazy



😢 1
Ian Fernandez17:04:33

yeah, breathing in and out everyday when I see this mess without tests

Ian Fernandez17:04:55

someone thought that could be a good idea to write a graceful shutdown engine using core.async


I mean - core.async/channels are a decent way to send a message


but a shutdown hook isn't exactly a good mechanism for that

👍 1

since you truly have no guarentees about what will happen


its like sending a message to Anakin melting in lava


What's the difference between timeout and Thread/sleep? I'm reading examples from this page:


timeout is async and Thread/sleep is blocking


That makes sense! Thanks!