Could someone point me in the direction of how I would [with clojure] read in a .yaml
modify it programmatically, then write out the modified version back to a .yaml
?
Note that the maintained fork of clj-yaml
is at https://github.com/clj-commons/clj-yaml I have an open pull request on Clojure Toolbox to update similar URLs.
I have not used either of the two libraries mentioned under the "YAML" category on the Clojure Toolbox page, but I would start by checking out the readme docs for those two libs: https://www.clojure-toolbox.com/
Thank you!
I just put a question on stack overflow (the code snippet seemed too long for slack). It's about transducer performance with and without using an async/chan
. https://stackoverflow.com/questions/65757419/understanding-clojure-transducer-performance.
Thank you for these interesting investigations!
it doesn't exactly answer your question, but maybe helps shed some light. chan-xf
and chan-then-nested
aren't necessarily analogous since chan-xf
is running the transducer before putting data on the channel while chan-then-nested
is running the transducer after taking data off the channel. I think the following is a better comparison and chan-xf
is about twice as fast on my computer:
(defn chan-then-nested []
(let [c (async/chan n)]
(async/onto-chan c (tx data))
(while (async/<!! c))))
(defn chan-xf []
(let [c (async/chan n xf)]
(async/onto-chan c data)
(while (async/<!! c))))
but it still doesn't explain your other example's result
if I was feeling a little more industrious, I might try to run your examples with https://github.com/clojure-goes-fast/clj-async-profiler
interesting. there seems to be a big difference between running the transformation before and running it after:
(defn chan-then-nested-before []
(let [c (async/chan n)]
(async/onto-chan c (tx data))
(->> c
(async/into [])
async/<!!
last)))
(defn chan-then-nested-after []
(let [c (async/chan n)]
(async/onto-chan c data)
(->> c
(async/into [])
async/<!!
tx
last)))
chan-then-before-before
is about 1.5-2x slower then chan-then-nested-after
Could it be that the transducer on the chan is just slow enough that it makes coordination between the two go loops (onto chan and a/into) more difficult and add more overhead? So in the tx version there are several (most?) items buffered by the time the takes are attempted, but with the xf version there is more waiting for a values to be ready by the async/into go block?
Like I could imagine that interleaving the producer and consumer go blocks would add more overhead then just filling a buffer then subsequently draining it
yea, something weird with the interleaving:
(defn chan-then-nested-before []
(let [c (async/chan n)]
(async/onto-chan c (tx data))
(->> c
(async/into [])
async/<!!
last)))
(defn chan-then-nested-before-doall []
(let [c (async/chan n)]
(async/onto-chan c (doall (tx data)))
(->> c
(async/into [])
async/<!!
last)))
chan-then-nested-before-doall
is significantly faster than chan-then-nested-before
Has anyone used Clojure (JVM, not Clojurescript) on serverless Google Cloud functions?
I’m getting an error when doing a post request that I’m not getting when doing a get request
here are my reitit routes
(defn home-routes []
[""
{:middleware [middleware/wrap-csrf
middleware/wrap-formats]}
["/" home-page]
["/api"
["/sign-in" sign-in]
["/upload-video" upload-video]]])
here’s my get and post request functions:
(defn http-get [uri params on-success on-failure]
{:method :get
:uri (str "<http://localhost:3000>" uri)
:params params
:on-success on-success
:on-failure on-failure
:response-format (edn/edn-response-format)
:format (edn/edn-request-format)
})
(defn http-post [uri params on-success on-failure]
{:method :post
:uri (str "<http://localhost:3000>" uri)
:params params
:on-success on-success
:on-failure on-failure
:response-format (edn/edn-response-format)
:format (edn/edn-request-format)
})
and here’s how the functions are being called:
(reg-event-fx
:upload-video
(fn [coeffects _]
{:http-xhrio (http-post "/api/upload-video" {}
[:upload-success]
[:upload-error])}))
I’m getting the following response:
{:response <!DOCTYPE, :last-method "POST", :last-error "undefined [403]", :failure :error, :status-text nil, :status 403, :uri "<http://localhost:3000/api/upload-video>", :debug-message "Http response at 400 or 500 level", :last-error-code 6}
how to fix this error?
There's not nearly enough code here to be certain, but I'm going to guess it has something to do with you using middleware/wrap-csrf
and not sending the CSRF token.
Hello is it possible to do something like the bellow? myns contains many clojure.core names that overrides
(:use myns :exclude clojure.core)
I tried 2 things that worked but maybe better ways
(def excluded-core-names '[get let ..])
(use `[myns :exclude ~excluded-core-names])
(:refer-clojure :only [])
(:use myns)
(:refer-clojure)
(:refer-clojure :only [])
works. Seems pretty clean. TIL!
(I deleted something I wrote earlier)
Is it weird that (conj)
returns a vector []
, but (conj nil 1)
returns a list (1)
, or am I overthinking it?
yes , its fine , i just left it like that 🙂 thanks
In Clojure nil
is not a collection of any type, so it is a design choice which collection type to return in both of those cases.
You can always control the return type of the collection by providing an actual collection to conj onto, and avoid both of those kinds of calls.
> so it is a design choice which collection type to return in both of those cases. But in these two cases the choice was different for each. Just wondering why that was
Understood. They both seem like easily avoidable cases by the way you call conj, if it bugs you, so should be irrelevant in typical Clojure programs.
I don't have any knowledge of whether there is some rationale given for that design choice, sorry.
Yeah, it's definitely not a big thing in practical terms. Thanks!
Both of those design choices seem to have been consistent since Clojure was originally published, circa 2006
The very same question has been asked just 9 days ago - Slack hasn't removed it yet: https://clojurians.slack.com/archives/C03S1KBA2/p1610095555367300
There's a thread with good explanations under that message.
Maybe I should make an http://ask.clojire.org quetion/answer out of it
> The very same question has been asked just 9 days ago
so it was, thanks! Even exactly the same thought process: the update
use case was what got me thinking about the (conj nil 1)
thing.
Though I'd say even after reading it I'm at the same place as didibus - unclear as to whether the difference is due to an intentional design decision or not.
conj
by default uses []
in its 0-arity.
Treating nil
as a sequence yields a list. No matter whether you're using conj
or into
or rest
or something else.
These two things are completely orthogonal.
Here: https://ask.clojure.org/index.php/10063/why-does-conj-returns-vector-conj-returns-list-conj-returns?
I think it is due to an intentional decision, but made at different times for different reasons.
Initially conj
only had a 2-arity: (conj nil 1)
or (conj [1 2] 3)
or (conj '() 1)
. This was in the time of sequences, and conj
was exclusively a sequence function. From that perspective, the question was, what should (conj nil 1)
return? And the logical answer was, we should probably treat nil
as the empty sequence
, so nil
should default to an empty seq and thus (conj nil 1) ;=> (1)
was made to return a seq.
IMO, as I said, lists are not about conj
at all:
user=> (type (conj nil 1))
clojure.lang.PersistentList
user=> (type (into nil [1]))
clojure.lang.PersistentList
user=> (type (rest nil))
clojure.lang.PersistentList$EmptyList
user=> (type (reverse nil))
clojure.lang.PersistentList$EmptyList
user=> (type (dedupe nil))
clojure.lang.PersistentList$EmptyList
So the initial question (if there even was one) was probably "what kind of collection should nil
beget" and not "what should (conj nil whatever)
return".
Later, conj
was evolves to also be a transducer
, which meant that a 0-arity
and a 1-arity
were added to it. Transducers are conceptually collections
functions, not sequence
functions. The 1-ary
in transducers is the completion
function, it says what to do at the end of applying a transducer, and in the case of conj
we don't need to do anything except return the result, thus the 1-ary
of conj just returns its argument as is, aka its an identity function.
Now the 0-ary
in transducers is the init
function, this will be called when there is no starting collection in order to decide what the default is, and it could be used to setup some other things related to the particular transducer. Now the question here was again, what should be the default when conj
is used in a transducer with no starting collection specified? In this case it was decided that would be vector, and this is because transducers are conceptually collection
functions, so defaulting to a sequence wouldn't make sense. Now you could ask why it didn't default to list, and I think that is because vectors are a nicer default here since they don't reverse the order of the elements when processed. Now when (conj nil 1)
was chosen, you could say hey but this was made a list and that reverses the order so what gives? Well, the rationale was different, for that it was about treating nil
and empty seq
as equivalent, since an empty seq
is a list it returns a list. Where as for transducers it wasn't about that, it was about what is a good init
collection for transducing over conj
if none are provided, and here vector
was chosen as the best one to pick from.
> So the initial question (if there even was one) was probably "what kind of collection should nil beget" and not "what should (conj nil whatever) return". That seems the same question to me?
Hum.. actually conj was never a sequence function hum... Might need to revise my answer a bit. Though I think it was the same idea, nil is often treated same as empty list, so I think that was the idea for conj as well
conj
has always worked to add a new element to any kind of collection, not only lists or sequences. It worked on sets, maps, and vectors from the beginning.
nil
being the empty list is a Common Lisp-ism, one that Rich explicitly rejected as a design decision for Clojure in most places -- mentioned in his talk on Clojure for Lisp programmers. In Clojure ()
is the empty list, not nil
. nil
is not a collection.
"But nil means nothing in Clojure. It means you have nothing. It does not mean some magic name that also means the empty list. Because there is empty vectors, and there is empty all kinds of things. "nil" means you do not have something. So either you have it, a sequence, or you have nothing, nil. If you have a sequence, it is going to support these two functions." part of this talk: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureIntroForLispProgrammers.md
Also if you search for "eos" in that transcript, there is a slide where he talks about nil vs. empty lists and a few other things, comparing what Common Lisp, Scheme, and Clojure do there.
If I want to cache a single value forever, is it OK to use something like:
(def cached-value (atom nil))
(defn compute [args]
(or @cached-value (reset! cached-value (real-compute args))))
(assuming the result is never false
so the use of or
is safe)Forgot to specify - real-compute
is pure. I don't care how many times it ends up being called in the end.
Why not just have compute wrap real-compute with memoize
?
I can't think of any reason that would be unsafe. You can also use delay
instead of an atom.
In your compute
function, if you ever call compute
with different args, that cause real-compute
to be called with those different args, and return different results, then you have a race which of those results ends up being stored in the atom.
(you have a race if you call real-compute
from multiple threads, at least)
Thanks, right! Apparently it was delay
that induced that itch that made me ask the question in the first place.
@robert.mitchell36 Because args
are costly to compare and I don't care if they're different. I only care about the very first time it's called.
Ah, bummer - delay
needs to create a closure and it needs to be stored somewhere. atom
it is then.
In that case, you could also use a promise.
Something like:
(def first-value (promise))
(defn compute [args]
(if (realized? first-value)
@first-value
(deliver first-value (real-compute args))))
> conj
by default uses `[]` in its 0-arity.
> Treating `nil` as a sequence yields a list¹.
Thankyou @p-himik, I finally see how this could be considered consistent! 🙂
¹ emph. added
A small correction to your code - seems like deliver
returns the promise itself, so it also needs @
.
Ah, right. Good catch!
Ah, and it can return nil
. So it's not really thread-safe, I think.
And promise
is just a wrapper on top of atom
. :D OK, I'll definitely stick with atom
.
Interesting stuff, thanks for discussion and links!
@andy.fingerhut What does "eos" stand for? Or what does it mean?
I haven’t read to confirm in detail, but IIRC in this context it means “end of sequence”
Thanks!
I think I'll put down conj as "practical, and probably consistent with implementation/usage/history while not necessarily formally self-consistent as in having simplest possible behaviour" until some future moment of enlightment 🙂
I think real-compute
might get called twice if your app is multithreaded. Maybe something like this would be better: (defn compute [args] (swap! cached-value (fn [v] (or v (real-compute args)))))
Just don't call conj
with 0 args, or a first arg of nil
, and these corner cases are unimportant to you.
When you say "it can return nil
, so it's not really thread-safe, I think", are you referring to promises?
@jkrasnay As I mentioned - I don't care if it's called multiple times. But your code snippet makes sense, thanks!
@andy.fingerhut Yes, promises. deliver
can return nil
.