Fork me on GitHub
#clojure
<
2020-01-15
>
Rutvik Patel04:01:53

Hey folks, need your help to choose a book. 1) Programming Clojure, Third Edition by @alexmiller (PC) 2) The Joy of Clojure, Second Edition by @fogus and @chouser (JOC) PC is relatively new (2018) and covers Spec as well. But it seem beginner friendly, and I know decent level of Clojure. JOC, on the other hand, people praise it for being an advance book but it's quite old (2014). I can only buy one of them, which one it should be?

hindol09:01:15

Don't know if you have read it, but Clojure for the Brave and True is free and comprehensive. Won't cover the "why" though.

papachan12:01:26

I enjoyed a lot The joy of Clojure by fogus

👍 4
Rutvik Patel04:01:37

@UJRDALZA5 Clojure for the Brave and True is for beginner, right? I'm looking for a book which covers advance topic. JOC2 seems to fit well though.

hindol04:01:31

Yes, it is for beginners but then it has a lot of content as well. It is worth glancing over it once.

Rutvik Patel04:01:55

Certainly I'll give it a try, Thanks @UJRDALZA5.

seancorfield04:01:45

@heyrutvik They're two very different books. Buy both. JOC is very much the "why" of Clojure -- the spirit and idiom of the language -- whereas PC is more about the "what" and the "how".

👍 8
Rutvik Patel04:01:38

Oh okay. It seem like I know "what" and "how".. it's time for "why". Thanks much!

seancorfield04:01:20

For what it's worth, JOC 1st ed was my first Clojure book but I'd done a lot of FP (and some Lisp) decades ago so the concepts weren't new to me. Clojure in Action (also 1st ed) was the book I bought almost immediately after that.

✔️ 4
wcalderipe04:01:10

Also, try not judge books by when they were published and yet by their content and if they survived the "proof of time". If a book still relevant after years it's probably a good book to read.

Rutvik Patel04:01:40

Right, lindy effect.. makes total sense. Thanks!

seancorfield04:01:48

Good point, overall, and certainly true of JOC2. But library structures and tooling have changed a lot, even tho' Clojure itself has been very stable and only evolves slowly.

wcalderipe04:01:30

Indeed, tools are always evolving for any active community. As a simple rule of thumb, the proof of time will be a good filter to start with - if people still recommend you the same old book it's probably worth to read.

wcalderipe04:01:48

brain-dumping: it might be a good idea include some books in the Clojure community survey :thinking_face:

👍 4
andy.fingerhut04:01:54

I have recently thought it would be nice to have a list of Clojure books, with curated reviews for whether you found a book helpful or not, relative to what background knowledge you came to them with. e.g. did you know Java already? Any other Lisp variant? Any Clojure knowledge previous to reading it?

andy.fingerhut04:01:22

New to programming vs. N years of experience?

andy.fingerhut04:01:28

Then based upon the answer to a few questions about. your background one could see a list of Clojure books that others with similar backgrounds found most helpful.

seancorfield04:01:44

Yeah, that's why I often hesitate to recommend books to beginners -- it's hard for me at this point to judge how good they are for that audience (35 years of programming and nearly nine of those in Clojure). I hear good things about Living Clojure and Getting Clojure for beginners and I hear quite a few folks recommending against Joy of Clojure as a "first Clojure book" 😐 I have all those books. I have almost every Clojure book available I think, several in more than one edition. Based on that, I'd probably recommend against almost anything from Packt (there are a couple of specific exceptions I think) and I wouldn't recommend either Clojure in Action edition these days (both were outdated at publication due to problems with Manning's editorial process).

seancorfield04:01:27

Clojure Programming (O'Reilly) is probably not worth buying these days either (but I thought it was excellent when it came out... in 2012!).

Rutvik Patel05:01:07

That's why I mentioned publication years.. books which depend on libraries or older version of compilers do affect the selection. I believe JOC2 uses clojure 1.6, whereas PC uses 1.9, and I use 1.10. And I don't know how much has changed since 1.6. Also, currently at job I use Scala so I'm familiar with FP and being Scheme fan, know LISP as well. So don't want to purchase beginner friendly book. FYA, currently reading Clojure Appiled.

seancorfield05:01:18

1.7: transducers, reader conditionals; 1.8: Socket server/REPL; 1.9: Spec, qualified key support in hash maps; 1.10: Java 8 required, datafy/nav, prepl, tap> -- and also in the 1.9 timeline: the new CLI/`deps.edn` machinery. I think that's a reasonable summary.

Rutvik Patel05:01:49

Wow.. that was quick. Thanks @U04V70XH6 🙂

v3ga13:01:34

Clojure Programming is still good. They have a pretty decent section going into Ring etc that I really needed.

👍 4
deleted04:01:09

Getting Clojure is really great, too

8
sogaiu05:01:10

among other things, i particularly appreciated the explicit mentioning of various gotchas.

didibus06:01:57

Is there a way to tell maven (well clj deps.edn) to grab the latest snapshot of a dependency?

didibus06:01:16

I thought that was what "LATEST" was for, but that seems to grab the latest non snapshot

didibus06:01:50

Basically, from: https://clojars.org/cider/cider-nrepl I'd want the most recent version which is: 0.23.0-SNAPSHOT

jumar07:01:53

iirc, the maven snapshot dependencies are updated once a day. There was a switch (`mvn -U`) which forces the update but I don't now about tools.deps

Alex Miller (Clojure team)13:01:38

tools.deps uses the default of once a day and there is not currently a way to change that (ticket exists for this). A workaround is to just delete the appropriate directory out of ~/.m2/repository

didibus04:01:04

Hum, I don't think that was my issue. It seems with version latest it's not pulling snapshot

didibus04:01:26

The snapshot had been there for a while

Eamonn Sullivan09:01:16

@heyrutvik, I just finished 1 and it was very good. It's relatively up-to-date (Clojure 1.9) too, which is helpful. I'm just starting Elements of Clojure (https://leanpub.com/elementsofclojure), but I've only read the introduction and a bit of the first chapter, so can't recommend it yet. I'll have a look at Joy of Clojure.

Rutvik Patel11:01:13

Oh, so you have finished PC 3rd edition? What's your background? I mean, how much Clojure you already knew before reading it, familiarity with FP?

Rutvik Patel11:01:02

Yeah, Elements of Clojure is in my to-read shelf. 🙂

Eamonn Sullivan11:01:56

I'm a Scala developer mostly, so I was already familiar with the functional concepts. I'm an emacs user, who does actually write the occasional elisp (so familiar with lisp) and have played around with Clojure on very small things, in the repl. I have started a big-ish personal project in Clojure/ClojureScript, so I wanted a good overview of the language and some hints on good style and design.

✔️ 4
Eamonn Sullivan11:01:15

I had also (too many years ago) read parts of Paul Graham's On Lisp and tried my hand at Common Lisp, but didn't get far back then.

✔️ 4
mloughlin11:01:56

I've just finished reading Elements of Clojure. It's a great supplementary/secondary text (and a very quick read). I plan to re-read the first few chapters on naming and idioms again soon.

👍 4
pbaille10:01:22

hi, i’ve encountered a weird error with core.match:

(m/match [1]
  [(x :<< inc)] x) 
;;=> "No method in multimethod 'to-source' for dispatch value: null"

dabrazhe10:01:07

Hi. I am curious why does the comp function have the reverse order of functions it applies to an argument? There should be some logic to it, eg like in the thread macro.

sgerguri10:01:21

The logic there follows that of mathematical function composition, which is done in the same order.

thanks3 4
dabrazhe11:01:08

yes, indeed it does. thank you!)

vemv11:01:02

it also can be understood as "lisp order": (comp a b c) == (a (b (c ...

vemv11:01:20

honestly I prefer to always read things left-to-right, past-to-present which is why I use a custom comp that works in the opposite order

littleli13:01:28

for inspiration in js functional word (ramda) they call such operation pipe see docs https://ramdajs.com/docs/#pipe

penryu11:01:13

I usually either think of ((comp f g) x) as the expanded (f (g x)), where f and g are in the same order as in the mathematical expression f · g. But sometimes I just read f · g as "f after g".

👍 4
vandr0iy13:01:31

Hi everyone! I've got this function:

(defn follow-cloudfront-invalidation-state
  [id]
  (loop []
    (let [state' (some-> id get-cloudfront-invalidation-state :invalidation :status)]
      (if (not= state' "InProgress")
        (println "> DONE: " state')
        (do (print "|")
            (Thread/sleep 1000)
            (recur))))))
The idea is to follow asynchronously the state of a lengthy task by printing out a | character every time a ping is sent - like a progress bar - and return as soon as certain value in the returned map changes. The thing is: If I invoke it in a future , like this: (future (some-> cloudfront-invalidation :invalidation :id follow-cloudfront-invalidation-state)) - it doesn't print my | characters gradually, in a progress bar fashion - it displays the entire thing as soon as the function returns. I'm clearly missing something obvious here; could someone point me to it?

vlaaad13:01:34

@vandr0iy probably (flush)

vandr0iy13:01:02

boom! that was it 😅 I knew it was something obvious!!! Thank you very much

vlaaad13:01:47

after (print "|")

craftybones14:01:12

Is there a way I can tell if a function has a body associated with it? I want to distinguish between (defn foo [x]) and (defn foo [x] (…))

Alex Miller (Clojure team)14:01:15

the first implicitly returns nil

Alex Miller (Clojure team)14:01:28

I don't know of any way to distinguish those function objects

craftybones14:01:53

I am giving an “assignment” where I’ve asked people to implement some functions. I want to provide a helper function that prints the results of all the implemented functions. I can always ask them to toggle something in the metadata in order to do it

Alex Miller (Clojure team)14:01:50

if you're doing something on their code as data, then you could definitely do it by syntactically examining the forms

craftybones14:01:49

No, not as of now, but I think I’ll just let them toggle the metadata for now. Thanks alex.

Eduardo Mata17:01:06

I am getting a error

java.lang.IllegalStateException: Attempting to call unbound fn: #'forecasts/processor

seancorfield17:01:21

@contact904 You'll need to provide a bit more detail about what you're doing and how you are running into that problem.

seancorfield17:01:52

Are you using a refresh/reloaded workflow?

Eduardo Mata17:01:16

Ok. So I have long term polling processor reading messages from redis. The redis message contains metadata that will pick the type of processor to run. my processors look like

(def processors
  {:adjustment [process-forecasts]
   :racks [process-forecasts]
   :in-system [process-forecasts]
   :batches [process-forecasts]
   :schedule [process-batches process-forecasts]
   :ticket [process-tickets]
   :terminal-actual [process-forecasts process-racks]
   :transfer [process-forecasts]})

Eduardo Mata17:01:37

let me elaborate more.

Eduardo Mata17:01:49

Basically, my long term polling processors subscribe to redis get the messages and uses async, to throw the data into a router function, then to a run function that runs the processor function.

(defn- run
  "Wrap the processor function in a try/catch to prevent crashes."
  [f entity]
  (timbre/info "RUNNING:" f entity)
  (try (f entity)
       (catch Exception e
         (timbre/error e))))

(defn- router
  "Route a `data` map to the correct processor based on the `:processor` key."
  [data]
  (let [delay (:delay data)
        processor (:processor data)
        processors (get processors processor)]
    (if (some? delay) (Thread/sleep delay) :default)
    (cond (nil? processors)
          (do (forecasts-logging {:message (str "NO PROCESSOR FOUND: " processor)})
              :processor-not-found)
          :else
          (doseq [processor processors]
            (run processor (:entity data))))))

(defn- data-in
  "Mount all necessary state and begin listening on the forecast Kafka topic."
  [data]
  (let [records (chan 131072)]
    (>!! records data)
    (async/go-loop []
      (when-let [data (<! records)]
        (if-not (empty? (:entity data))
          (router data)
          (forecasts-logging {:message "Empty entity"}))
        (recur))))
  (dissoc data :payload))

Eduardo Mata17:01:19

in the processors variable the value of the keyword is a function that IS NOT private

seancorfield17:01:58

And that def is in the same namespace, above those functions? Or in a separate namespace that you're requiring? And those process-* functions are all defined above processors in that namespace?

Eduardo Mata17:01:56

Yes, they are in the order you see them in the exact same namespace

Eduardo Mata17:01:18

process-* are in their own namespace.

Eduardo Mata17:01:30

some processors call the same function

hiredman17:01:10

have you restarted your repl recently?

hiredman17:01:22

the error message is complaining about a var #'forecasts/processor which isn't in the code you shared, so my guess is you have some bad state in you repl left over from previous interactions

Eduardo Mata17:01:53

I restarted the jar file, and yes, it worked after restarting it

hiredman17:01:51

I think you at some point had a processor defined, and had some go loops(or threads) running that call it, then changed your code, and used some kind of reloader which deleted the vars but you never stopped the go loops(or threads) and those kept running and tried to call functions using the now deleted vars

zara22:01:07

I need some help with this situation:

rob23:01:37

I'd love to have a reader macro that would take a symbol and prepend it with as a keyword. So something like {+:foo} would be {:foo foo}.. Feel like I type things like this that all the time. Has anyone come across anything like this? You can do something superficially similar in ocaml, and I miss it!

noisesmith23:01:42

that's impossible because the reader rule that a map must have an even number of keys is applied before your reader macro is

noisesmith23:01:59

also custom reader macros need to start with #, not +

noisesmith23:01:24

clojure isn't intended to have very flexible reader macros, iirc that's on purpose

noisesmith23:01:55

you can do it by forking clojure and implementing from scratch of course, or using an external preprocessor

noisesmith23:01:05

but it won't be integrated into core

andy.fingerhut00:01:44

Well, it will be integrated into core if Rich Hickey really wants it. 🙂 As it should be, of course. I doubt he really wants it.

noisesmith00:01:35

yeah - I don't recall the specific citation, but my recollection was that he was pretty opinionated about the kind of reader macros clojure would support

rob23:01:52

welp. that'll do it, thanks -- fwiw, the + was just meant to be visibly different then current reader macros.. thanks for the exhaustive answer lol

noisesmith23:01:25

haha, np - at one point it was a faq (when we had more people from the common lisp world checking out clojure...)

rob23:01:27

probably not worth a fork.. anyway, I didn't know you could provide custom reader macros so that's cool. Is it just "dispatch" (`#`) macros ?

noisesmith23:01:59

also, you can construct the map via macro (just not as a literal like that) - I'll dig the macro up it's surprisingly simple

rob23:01:02

no worries, I know how I could construct a map w/ regular macro

noisesmith23:01:48

(ins)user=> (defmacro locals [] (into {} (map (juxt (comp keyword name) identity)) (keys &env)))
#'user/locals
(cmd)user=> (let [a 0 b 1] (locals))
{:a 0, :b 1}
(ins)user=> ((fn [x] (let [a 0] (locals))) 42)
{:x 42, :a 0}

👍 8
noisesmith23:01:41

the "magic" here is a hidden &env arg to macros which captures local bindings

noisesmith23:01:13

the vals are only useful to the compiler, the keys have the names of the bindings as symbols

🆒 4
rob23:01:48

neat -- that wasn't what I expected !

dpsutton23:01:31

I think there’s a big thread on clojureverse about a macro for this. I like the idea

noisesmith23:01:04

the useful lib has a version where you need to explicitly list the keys you want

noisesmith23:01:47

for me, I use the above macro when debugging to capture and print and/or persist data and it's just a lot more convenient to grab all visible locals