Fork me on GitHub
#clojure
<
2022-11-16
>
Eric Scott15:11:31

Hey is there a Clojure cookbook more actively maintained than the link below that's pretty much the go-to that everyone uses?

Eric Scott16:11:56

This is great, but unless I'm missing something this answers questions mainly about how to use a given Clojure API feature. My impression of a cookbook is more goal-oriented and higher-level: "how do I read a csv file?"; "How do I build an uberjar using the clojure CLI?"

Eric Scott16:11:24

Bonus points for an Encyclopedia of Error Messages

😂 1
seancorfield18:11:35

Have you looked at the Clojure Applied book?

Eric Scott18:11:38

I note that the copyright is 2015, according to the Amazon website preview.

andy.fingerhut18:11:55

Clojure the language has grown by adding new features, not removing old ones, so pretty much everything that 2015 book says is still true of Clojure today, with perhaps minor issues like "there might be new features it does not describe, that in some cases would be recommended over the older-feature-limited ways of doing them"

Eric Scott18:11:35

Yes, but best practices change over time. For example, I would expect a 2015 book to mainly talk about using leiningen to do your project management.

Eric Scott18:11:24

I guess what I had in mind was some kind of crowd-sourced endpoint that had a lot of buy-in in the community.

andy.fingerhut18:11:10

http://clojuredocs.org is crowd-sourced, but focused on usage and examples of individual functions and macros.

andy.fingerhut18:11:21

not Leiningen, boot, tools.deps, etc.

andy.fingerhut18:11:06

Clojure for the Brave & True includes notes on setting up Emacs as a Clojure IDE and using Leiningen (if I recall correctly), but doesn't mention other IDEs or tools.deps, and is not crowd-sourced but written by an individual.

seancorfield18:11:24

The main change the author would make to Clojure Applied I think is less reliance on records and more reliance on plain old hash maps -- that seems to be the sentiment of Alex's comments about the book, should a 2nd edition happen.

andy.fingerhut18:11:35

There might be something that covers more language + IDE + build/release process, but others would have to provide those recommendations, as I'm not aware of them.

seancorfield18:11:21

I'll also point you at https://clojure-doc.org/ which is more focused on "cookbook" style material (but really needs more contributions from the community -- hint, hint, people!)

👍 3
Eric Scott18:11:33

Yes. That's exactly what I had in mind. I recalled seeing this some time ago, and should've bookmarked it.

Eric Scott15:11:26

(and contributes to)

seancorfield18:11:21

I'll also point you at https://clojure-doc.org/ which is more focused on "cookbook" style material (but really needs more contributions from the community -- hint, hint, people!)

👍 3
jpmonettas19:11:25

is there a way of serializing to edn with pr-str when *print-level* and *print-lenght* are involved? or a similar way of serializing a big nested data sctructure with something similar to define some limits?

phronmophobic19:11:47

I'm kind of assuming that the problem you're getting at is something like: There is an out of process user interface and it would be nice to show large or potentially infinite values in the UI. Clerk does a similar thing with their viewers. They way they solve it with a budget that gets enforced in a present step. https://github.com/nextjournal/clerk/blob/main/src/nextjournal/clerk/viewer.cljc#L1150

jpmonettas19:11:56

the problem I have it that pr-str can generate non edn, since it will spit things like [1 2 ...] , adding the dots when you hit the limit, but then it can't be read back with clojure.edn/read-string

phronmophobic19:11:34

There are a number of dynamic variables that affect pr-str. You can explicitly set them. My current method for writing readable-edn is:

(defn ->edn [obj]
  (binding [*print-length* nil
            *print-level* nil
            *print-dup* false
            *print-meta* false
            *print-readably* true

            ;; namespaced maps not part of edn spec
            *print-namespace-maps* false]
    (pr-str obj)))

phronmophobic19:11:27

There are still a few issues even with that since you can have in-process keywords/symbols with spaces in them, but the above won't generate readable edn.

jpmonettas19:11:01

yeah I haven't found anything that works yet

phronmophobic19:11:13

I think clerk has some workarounds for this as well

jpmonettas19:11:18

like :

(binding [*print-length* 5
                *print-readably* true]
        (pr-str (range 10)))

"(0 1 2 3 4 ...)"

jpmonettas19:11:37

so even if you set print-readably true, it will print that

phronmophobic19:11:45

you have to set *print-length* to nil

jpmonettas19:11:00

but I need the limit

phronmophobic19:11:25

if you need some sort of budget, then I recommend doing what clerk does and having a "present" step that enforces the budget.

jpmonettas19:11:39

I'm sampling some info, and I don't want to store to a file a million elements from a collection,if I only need 3

jpmonettas19:11:56

will take a look at that

jpmonettas19:11:58

hmm not sure how to use that without re-writing an entire serialization thing

phronmophobic19:11:13

I think the key idea is to separate it into two steps: 1. generate a tractable size value from a large value 2. serialize Since you don't really care about customizing "presenters", you might be able to get away with doing a prewalk transformation with something like clojure.walk/prewalk, zippers, or specter

😃 1
jpmonettas19:11:38

I guess I will have to do something like that

jpmonettas19:11:17

it would be much easier if this "..." was also customizable with a dyn var

src/clj/clojure/core_print.clj
59:                (.write w "...")

src/clj/clojure/pprint/pprint_base.clj
191:        (print "...")
401:         (.write ^java.io.Writer *out* "...")))))

jpmonettas19:11:44

those are the places it is adding them

jpmonettas19:11:42

if it prints :... would be already redable

jpmonettas19:11:01

I guess I'll just hack it and do a replace ... with :... before spitting it into a file XD

phronmophobic19:11:03

I'm not sure the use case where someone wants to print readable data that is truncated is all that common.

phronmophobic20:11:24

Generally, I think people either want something to print to the console that is human-readableish or print all the data in a machine readable way

phronmophobic20:11:48

and most people explicitly don't want an in-between option that silently drops data

jpmonettas20:11:22

my use case is that I'm experimenting with a fn type sampler. I'm instrumenting entire codebases so when it runs I can sample fn types (args and returns) and also "call examples", storing everything into a edn file to render it after as documentation

borkdude20:11:41

if you just want a sample, then why not set the length to some arbitrary large number?

jpmonettas20:11:17

so lets say you are creating examples for map, and someone called (map inc (range 1000000)), you probably just want (map inc (0 1 2 3 ...)) in your call example

jpmonettas20:11:33

does it make sense?

👍 1
phronmophobic20:11:14

yea, your use case totally makes sense. Based on my experience with making https://github.com/phronmophobic/viscous, I think you'll probably want to have your own way of displaying a short summary of a value rather than something generic that pr-str might conceivably provide.

jpmonettas20:11:34

yeah, I'll go with something like this first:

(defn serialize-val [v]
  (binding [*print-length* 5
            *print-level* 3]
    (str/replace (pr-str v) "..." ":...")))
just to keep moving

👍 1