If I have a function which only contains a loop inside, is there some cleaner way to write this, without obfuscating the loop variable names somehow?
(defn my-func
[arg1 arg2 & rest]
(loop [a1 arg1 a2 arg2 r rest]
...))If you don't need the original values arg1, arg2, rest, you can just reuse the names:
(loop [arg1 arg1
arg2 arg2
rest rest]
...)
And at that point, you can remove the loop altogether and recur to the function call itself.
BTW, just in case - I'd advise against using rest as a name. It shadows a built-in clojure.core.rest which, if you aren't careful, can lead to sometimes rather hard to debug issues.Thank you! I wasn't aware I could reuse variable names like that, or use recur without a loop. Also thanks for the heads-up on using rest, do you have any advice for a function named "read"? should I manually namespace the function like "prefix-read"?
The answer is "it depends".
I myself try to avoid shadowing vars with locals, but somehow I'm more or less fine with shadowing a var from clojure.core with my own var - granted that there's (:refer-clojure :exclude [that-var]) in the ns form to make the shadowing explicit and to avoid the corresponding warning.
If read is just the perfect name for that function, I would use it and add read to the exclusions from clojure.core.
If the name can be altered a bit without sacrificing anything, I'd change it so avoid the exclusion hassle and to guarantee that there will be no accidental usages of your.ns/read where clojure.core/read was meant to be used.
But I should also add that I almost never use :use or :refer. I almost exclusively use (:require [some.ns :as alias]) and then do alias/some-var, so all the context is crystal-clear.
It doesn't help when you need to use read in that same namespace, but it definitely helps if read is intended to be used by other namespaces.
(def my-func #
(loop [arg1 %1 arg2 %2 r %&]
...))Are there any downsides of using recur without loop? I mean, we want to have real real tail recursion. I heard a few times, that we will not get it because of JVM limitations. But we have it already. ?
Fn bodies and method bodies (in things like reify, etc) have implicit loops
So in effect you cannot use recur without loop, as those are the only places you can use it
Thinking out loud here: might/should there be an approach to logging where you can “catch” a log emission so it can be associated with a particular execution stack. Eg.
(do
(log "Calling frob for" user)
(frob "I, frob, will be calling (log \"Frobnication took 4324ms\") but I don't know \`user\` and don't want to have to know just for the sake of the log message))
so you’d want these two log messages associated, conceptually the lower one “indented” under the higher onehow would the outer context know to drop the inner context?
Unless you're going to write something like (try (stateful-log) (stateful-log) (stateful-log) (finally (clear-log-state)))
Could be regarded as "a poor man's MDC", or maybe the other way around
MDC not familiar to me
yeah, i was going to recommend MDC depending on what you need
Picturing logging output like
[timestamp] Frobbing for John >> [timestamp] I, frob...
So, mulog has something sort of like what you describe, if you use a trace, it'll associate all following logs in that execution-chain with a parent ID
(but, of course, its all just maps, not kindly-formatted string-outputs)
"mapped diagnostic context" - a feature of Log4j (and maybe others) - a way to stuff key/value pairs into a thread-local that the logging framework includes in log messages, basically, IIRC
MDC is less beautiful than @james.amberger had in mind, but on the other hand the log statements are not coupled at all
ok interesting
(And sometimes a bird in the hand is worth two in the bush)
(afk)
flowstorm also has similar features https://flow-storm.github.io/flow-storm-debugger/user_guide.html#_printer
(MDC/put "user_id" (str ...))
(try
...
(finally
(MDC/remove "user_id")and then in most slf4j compatible things there is a way to get this info into the log line
looking at the docs now I also see this
(with-open [_ (MDC/putCloseable "user_id" (str ...)]
...)and i'm sure clojure logging adapters expose all this in their own way + some might provide different mechanisms
one thing to note about MDC is it's only strings, so you have to do JSON generation if you want to pass objects
(ns main
(:require [clojure.tools.logging :as log])
(:import (org.slf4j MDC)))
(defn -main
[]
(with-open [_ (MDC/putCloseable "user_id" "123")]
(log/info "Hello"))
(log/info "world"))
[main] user_id=123 INFO main - Hello
[main] INFO main - world
Hey everyone, it's me again, haha. I want to create a conditional in my Clojure API. Can anyone help me? Please teach me how to use the schema checker. After using it, it works, but it doesn't return the message in POSTMAN. Can anyone help me? I am trying to make this:
(if (= (s/check model/schema-keyword-age body) nil)
(spit file-path/file-path
(json/write-str updated-list)
{:status 200
:headers {"Content-Type" "application/json"}
:body {:message (str "sucess!")}})
{:status 400
:headers {"Content-Type" "application/json"}
:body {:message (str "fail")}}))
In the IDE logs they show me these messages, but in POSTMAN I get the 500 and the internal server error: exceptionwhat is the exception’s message?
spit takes multiple arguments, but that return of “success” seems to be passed as the options to spit which is almost certainly not what you want
and can i propose a simple way forward? Replace the conditional with something trivial until it is working and then change it to be more complicated with what you actually want to check
(if (even? 4)
{:status 200
:headers {"Content-Type" "application/json"}
:body {:message (str "sucess!")}}
{:status 400
:headers {"Content-Type" "application/json"}
:body {:message (str "fail")}})get this working. then switch to odd?. Then use the repl to make sure you understand how s/check works, then replace the s/check call over the even? or odd? call
If you don't have some middleware setup to transform the response into json then returning a map like that in :body may error
ah. it should be fine, but i guess it should be "\"fail\"" ?
(cheshire.core/generate-string "fail")
"\"fail\""good eye
It is a map though, the string is under the :message key
oh you are right. i just spaced out on that. it looks so close to the ring map i glossed over it
Hello, thanks for the answers!! The first option that @dpsutton passes works to return the message:
(if (= (s/check model/schema-keyword-age body) nil)
{:status 200
:headers {"Content-Type" "application/json"}
:body {:message (str "sucess!")}}
{:status 400
:headers {"Content-Type" "application/json"}
:body {:message (str "fail")}})
but I have to put this:
(spit file-path/file-path
(json/write-str updated-list))
so when i do this it doesn't work:
(if (= (s/check model/schema-keyword-age body) nil)
(spit file-path/file-path
(json/write-str updated-list) {:status 200
:headers {"Content-Type" "application/json"}
:body {:message (str "sucess!")}})
{:status 400
:headers {"Content-Type" "application/json"}
:body {:message (str "fail")}})
you can help me with this, I would be very grateful!!!(do (spit …) {:status 200 …})
if takes a test and then two “branches”. to combine two expressions into one you can use do
Yessss!!!! I did it like this:
(if (= (s/check model/schema-keyword-age body) nil)
(do (spit file-path/file-path (json/write-str updated-list)) {:status 200
:body {:message (str "A idade do usuário " name " com o id " user-id ", foi alterado de " old-age " anos, para " new-age " anos com sucesso!")}})
{:status 400
:body {:message (str "A idade do usuário " name " com o id " user-id " não foi alterada. Verifique se o campo "age" está preenchido corretamente.")}})))
Now it's works, this function executes the logic and returns the message to the POSTMAN
Thanks man, you're awesome!!!glad you are unblocked!