Hi all, I am following the caveman tutorial on web development, and one of the chapters start using proletarian.worker and it just non-stop logging during idle just took a few gb from my ram. is there any way i can set it correctly?
There's a #caveman channel so maybe someone there has run into this?
ok thank you!
There’s also a #proletarian channel, and the docs helping you configure logging. I’ve personally made it so that it doesn’t log the polling of jobs cuz it’s kindof useless, and made it poll less frequently as well (default is 100ms or something)
PS options are very well documented in the docstrings for the worker function and the function to put jobs on the queue
wonderful! I went to check the docstring and finally slows down
Can someone explain why filter of a hash-map produces a list of vectors and not just a filtered hash-map? So
(filter identity {:a "a"}) ;; returns ([:a "a"]) and not {:a "a"}
I seem to always have to use into {} a lot."It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures." -Alan Perlis filter is a sequence function, so perhaps your real question is, "why does my map wilt into a sequence of pairs to fit into filter?" I think in the end you will be happy that it does! You can certainly make your own "filter-map", but you might begin to notice times you don't want to use it. Reinserting into a map is work that need not always be done.
I imagine that more than it being a matter of "100 functions on one data structure", the reason filter and map do not preserve the input's "type" is that they're already specified to return a lazy sequence, which is itself a "particular" kind of sequence and not a map/vector/set/whatnot; compare filterv which is specified to return a vector.
As an aside, if you do find yourself in need of that kind of polymorphic transformations, you might consider looking into libraries like specter.
Thanks @phill and @doppiaelle1999!
With transducers, I'd say that into {} is fairly idiomatic:
user=> (into {} (filter identity) {:a 1 :b 2})
{:a 1, :b 2}
user=> (into {} (filter (comp even? val)) {:a 1 :b 2})
{:b 2}In Clojure MapEntries are generally modeled as Vectors.
If you called (type ...) on them they would likely say clojure.lang.MapEntry. What's confusing is they print like vectors.
So what you are getting is a list of map entries
I think in theory it's faster to into a list of map entries back into a map. Not sure how much faster.
Thank you all, as always very friendly and insightful answers. I really love the clojurians slack.
I had a look at specter which seems a bit heavy handed for just my use case. Also, I haven't figured out if using libs like this would break if I was using ClojureCLR, bb or nbb.
Probably this is an OO/typed system mental deformation, but for me this is not https://en.wikipedia.org/wiki/Principle_of_least_astonishment. I'd be interested if other #beginners have struggled with this too?
Yes, specter is quite heavy handed, but that's just a consequence of what it sets out to do.
With respect to POLA, if you think about it map, filter and the likes take an iteration/sequence and return another in more or less every other language, so it probably would've been more unexpected if Clojure did it differently.
And as far as I see, it's the likes of into and conj that do act differently w.r.t. the input that are most astonishing to beginners (e.g. conj appending at the front on lists and at the back on vecs).
@doppiaelle1999 agreed, maybe the POLA part is more on the side of "why aren't maps iterable in their native form". However, the outcome is the same: filter gives you something else back than you put in. And that is not my mental model of filter (the stress being on "my")
> why aren't maps iterable in their native form
Because they're not conceptually iterable as a unit. Map keys, values or entries are, though. Clojure makes maps iterable by converting them to sequences of entries. Then filter's behavior makes sense: entries in, entries out.
Perhaps filter isn't really the operation you're looking for; maybe you want to dissoc the keys you want to "filter out".
I would say that POLA is maybe not applicable here? This isn't a user interface to sell products to your grandma and make it easy for non technical users. I think the question is more of if this choice is useful for common use-cases of filter over maps and if it composes itself naturally with other functions and data-structures in Clojure without too much ceremony needed.
This is likely not recommendable, but suppose you have a top-level macro that takes no arguments. Is it possible for it to provide the next form?
I have sketched a way to do this by using (:line (meta &form)) and providing the filepath with *file* . Would this be the only way to do it?
What do you mean by "provide the next form"?
e.g.
(mymacro)
(def myid [x] x)
the return value of mymacro would be \backquote (def myid [x] x)I mean its macroexpansion
this would shadow myid in normal execution
Apart from indeed being quite not recommendable, why would you want to achieve something like that?
Since the macro is expanded above the definition of myid, it would not shadow it - on the contrary.
right not quite shadowing, the file would become instead, after macroexpansion
(def myid [x] x)
(def myid [x] x)
I want to make a macro with this capability so that I could automatically create declarations like,
(def _myid-debug [x]
(do
(println x)
x)
(def myid [x] x)it would be exclusively in a test-time/non-prod setting so I think this could possibly make it more acceptable (maybe?)
especially if the macro has something like:
(if global-test-time-enabled-boolean `(def myid ...) nil)I see. It might make sense to do it in some contexts - and yes, the way you did it is the way to do it since AFAIK it's the only way to get the actual form of a var. But I would first reach out to more conventional things and use such a macro iff nothing conventional works in your use case. The most obvious conventional thing is instrumentation. Just call some function that alters all the vars you're interested in.
hm right, instrumentation as in specifically the clojure.spec.alpha utils or, instrumentation in a more general sense?
In a general sense.
(ns a.b)
(defn myid [x]
x)
and in some completely different dev-only file
(ns dev
(require [a.b])
(alter-var-root #'a.b/myid (fn [f]
(fn printing-wrapper [& args]
(println args)
(apply f args))))
As a side note - println could screw things up if you use lazy sequences.
Consider tap>. It's also something you can just leave in your code, even in production.Of course, with the example above in order to guarantee that none of such functions are called before they're instrumented, loading your namespaces has to be not side-effecting. A common way to achieve it is to have two main entry points - one for production and another for development, that's basically the one you use in production, plus all the instrumentation and whatnot.
woah okay this is a very neat workflow I had not known about, tyvm for the references I'll look into both alter-var-root and tap>, and ty a lot for the example this is super useful
There are also libraries that add tracing, such as https://github.com/clojure/tools.trace
did not know of it, ty!
Cider also supports tracing by default: https://docs.cider.mx/cider/debugging/tracing.html
As an aside. I think you were trying to mimic what in some other languages are annotations? Where you declare something above. In Clojure (and Lisps), you need to embrace the nesting nature of the syntax. So your macro would be much better if it wrapped your def:
(mymacro
(defn myid [x] x))
This would be more conventional.
Otherwise like others said, instrumentation is the other approach which is more "annotation" like. Instrumentation doesn't receive the source form though, but the evaluated form. You can use it to wrap things, do stuff before or/and after, but not majorly transform the form itself like with a macro. Which is enough for your use case.I just now saw your replies, thanks a lot! I will look deeper into cider's tracing