Fork me on GitHub
#beginners
<
2024-01-08
>
teodorlu16:01:36

Hi! Is it possible to get cheshire.core/generate-string to pretty-print json with 4 spaces instead of 2? I’m using cheshire to rewrite some json files in a repo, and I don’t want to change existing formatting.

teodorlu16:01:04

I’m getting two spaces like this:

user=> (println (json/generate-string {:x 1 :y 2} {:pretty true}))
{
  "x" : 1,
  "y" : 2
}

teodorlu16:01:02

Aaah, awesome! That’s exactly what I wanted. Thank you! 🙏

teodorlu16:01:29

In case anyone else is interested, this is what I did:

(def -cheshire-pretty-printer
  (let [opts (assoc json/default-pretty-print-options
                    :indentation "    ")]
    (json/create-pretty-printer opts)))

(defn json-generate-string [x]
  (json/generate-string x {:pretty -cheshire-pretty-printer}))
Worked perfectly. Thanks again!

Nim Sadeh21:01:29

X-posting as there's no traffic in clj-http

hiredman21:01:52

Content-Type is a header

Nim Sadeh21:01:33

That's true, but didn't solve the issue I get Unhandled RuntimeException: Invalid token :

hiredman21:01:49

generally the fragment of clojure that is exchanged as a data serialization format is called "edn" and I don't believe there is a registered mime type for it, but I suspect application/edn is most used

hiredman21:01:12

what does the rest of the stacktrace say

Nim Sadeh21:01:52

Show: Project-Only All 
  Hide: Clojure Java REPL Tooling Duplicates  (33 frames hidden)

1. Unhandled java.lang.RuntimeException
   Invalid token: :

                 Util.java:  221  clojure.lang.Util/runtimeException
           LispReader.java:  412  clojure.lang.LispReader/interpretToken
           LispReader.java:  305  clojure.lang.LispReader/read
           LispReader.java: 1398  clojure.lang.LispReader/readDelimitedList
           LispReader.java: 1355  clojure.lang.LispReader$MapReader/invoke
           LispReader.java:  285  clojure.lang.LispReader/read
           LispReader.java: 1398  clojure.lang.LispReader/readDelimitedList
           LispReader.java: 1347  clojure.lang.LispReader$VectorReader/invoke
           LispReader.java:  285  clojure.lang.LispReader/read
           LispReader.java:  216  clojure.lang.LispReader/read
           LispReader.java:  205  clojure.lang.LispReader/read
                   RT.java: 1876  clojure.lang.RT/readString
                   RT.java: 1871  clojure.lang.RT/readString
                  core.clj: 3816  clojure.core/read-string
                  core.clj: 3806  clojure.core/read-string
                client.clj:  478  clj-http.client/coerce-clojure-body/fn
                client.clj:  477  clj-http.client/coerce-clojure-body
                client.clj:  470  clj-http.client/coerce-clojure-body
                client.clj:  545  clj-http.client/eval11811/fn
              MultiFn.java:  234  clojure.lang.MultiFn/invoke
                client.clj:  563  clj-http.client/output-coercion-response
                client.clj:  560  clj-http.client/output-coercion-response
                client.clj:  574  clj-http.client/wrap-output-coercion/fn
                client.clj:  250  clj-http.client/wrap-exceptions/fn
                client.clj:  728  clj-http.client/wrap-accept/fn
                client.clj:  750  clj-http.client/wrap-accept-encoding/fn
                client.clj:  711  clj-http.client/wrap-content-type/fn
                client.clj:  959  clj-http.client/wrap-form-params/fn
                client.clj:  993  clj-http.client/wrap-nested-params/fn
                client.clj: 1017  clj-http.client/wrap-flatten-nested-params/fn
                client.clj:  893  clj-http.client/wrap-method/fn
               cookies.clj:  128  clj-http.cookies/wrap-cookies/fn
                 links.clj:   63  clj-http.links/wrap-links/fn
                client.clj: 1046  clj-http.client/wrap-unknown-host/fn
                client.clj: 1174  clj-http.client/request*
                client.clj: 1167  clj-http.client/request*
                client.clj: 1180  clj-http.client/get
                client.clj: 1176  clj-http.client/get
               RestFn.java:  423  clojure.lang.RestFn/invoke
         message_store.clj:   49  server.message-store/get-conversations
         message_store.clj:   47  server.message-store/get-conversations
                      REPL:   55  server.message-store/eval14934
                      REPL:   55  server.message-store/eval14934
             Compiler.java: 7194  clojure.lang.Compiler/eval
             Compiler.java: 7149  clojure.lang.Compiler/eval
                  core.clj: 3215  clojure.core/eval
                  core.clj: 3211  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1990  clojure.core/with-bindings*
                  core.clj: 1990  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  218  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  217  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java: 1583  java.lang.Thread/run

Nim Sadeh21:01:19

Output of the API is an array in case that matters

Nim Sadeh21:01:31

Maybe EDN can't handle that, idk

hiredman21:01:33

that isn't going to work

hiredman21:01:56

:as :clojure basically means "call the clojure reader on the body of the response"

Nim Sadeh22:01:33

Why wouldn't that work but :json would?

hiredman22:01:52

because the api is replying with json encoded data not edn encoded data

hiredman22:01:00

the clojure reader doesn't read json

Nim Sadeh22:01:27

Got it. I thought the coercion meant there was some client-side code that literally coerced the data using some defaults into Clojure if possible

hiredman22:01:40

:json does that

Nim Sadeh22:01:48

So :clojure is more commonly used for clj <-> clj communciations then?

Nim Sadeh22:01:01

Since most APIs don't use Clojure as the data transfer format

Umar Mahmud23:01:37

How can I return early from an operation in Clojure? For example, this is a typical pattern from imperative style languages:

condition_is_met = False

for i in collection:
    if my_function(i) == some_result:
        condition_is_met = True
        break
    else:
        continue
I am allowed to exit the loop when I get my result. What would be the functional equivalent of this in Clojure? I have written a small function to find the greatest common denominator of length of two sequence here:
(defn get-gcd [x y]
  (let [shorter (if (<= (count x) (count y)) x y)
        longer (if (= (count x) (count shorter)) y x)]
    (apply max (for [r (reverse (range 1 (+ 1 (count shorter))))]
      (if (and (= (mod (count longer) r) 0) (= (mod (count shorter) r) 0)) r 0)))))
I get back a whole sequence and then I am applying the max function on the sequence to get a result. In Python, I would just loop and exit with break statement on finding my result. The get-gcd function above does not feel like idiomatic Clojure to me nor does it feel functional. Also, if my collection is really large, then the for comprehension above would feel wasteful since I am getting back an entire sequence. Any ways I can return early from operations in a functional manner?

Sam Ferrell23:01:53

for returns a lazy sequence, so you can write (first (for [... :when foo?] ...)) to stop after the first :when foo?

Bob B23:01:38

other common patterns for 'early return' include not recurring and using the reduced function (in the context of a reduce)

Sam Ferrell23:01:52

there are several methods to return early in function languages... most fundamentally using recursion

hiredman23:01:52

it doesn't matter if for is lazy, or whatever, max has to traverse the whole thing, and you would have to traverse the whole thing to find max in python as well

hiredman23:01:47

finding the max for a sequence of numbers is not a good example for early returns, because it cannot return early

Bob B23:01:10

in this case, since the sequence starts in descending order, rather than building a sequence of zeroes, it would be possible to just filter that sequence to the elements where the divisor divides both subjects, and then the first thing in that list will be the max, so then the use of max becomes unnecessary, and the operation can be lazy-ish

Umar Mahmud23:01:09

yes, usage of the max function will become un-necessary if for is lazy and I can get some guarantee of the order of the sequence that is being generated by the for.

Umar Mahmud00:01:12

thanks for the pointers @U02FVPF04A1 @U013JFLRFS8 @U0NCTKEV8. This is good information for me as a beginner to Clojure.

kennytilton15:01:16

For the original use case, (some my-function collection) will "short circuit". Recursive functions can stop when they like by not recurring. Beyond that, back in the good old days of Cobol I spent a couple of hours helping someone on an inexplicable bug. Finally in a daze I scrolled up a few pages. An early exit (above the fold so we did not see it) made the behavior explicable. :face_palm: