beginners

David Ko 2025-06-01T00:43:11.907559Z

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?

seancorfield 2025-06-01T00:55:27.304129Z

There's a #caveman channel so maybe someone there has run into this?

David Ko 2025-06-01T00:55:43.433239Z

ok thank you!

Patrix 2025-06-01T01:04:25.975909Z

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)

👍 1
Patrix 2025-06-01T02:38:06.073689Z

PS options are very well documented in the docstrings for the worker function and the function to put jobs on the queue

David Ko 2025-06-01T03:44:28.124789Z

wonderful! I went to check the docstring and finally slows down

👍 1
Gregory Bleiker 2025-06-01T11:20:51.588419Z

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.

2025-06-01T11:30:04.473299Z

"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.

exitsandman 2025-06-01T11:53:09.618789Z

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.

Gregory Bleiker 2025-06-01T12:28:15.936359Z

Thanks @phill and @doppiaelle1999!

seancorfield 2025-06-01T14:42:18.791579Z

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}

➕ 2
2025-06-01T15:30:28.129679Z

In Clojure MapEntries are generally modeled as Vectors.

2025-06-01T15:32:37.291819Z

If you called (type ...) on them they would likely say clojure.lang.MapEntry. What's confusing is they print like vectors.

2025-06-01T15:33:31.814479Z

So what you are getting is a list of map entries

2025-06-01T15:39:47.365129Z

I think in theory it's faster to into a list of map entries back into a map. Not sure how much faster.

erwinrooijakkers 2025-06-06T12:48:51.625969Z

erwinrooijakkers 2025-06-06T12:49:57.414899Z

https://youtu.be/cPNkH-7PRTk?t=37m30s

Gregory Bleiker 2025-06-02T07:05:18.166549Z

Thank you all, as always very friendly and insightful answers. I really love the clojurians slack.

Gregory Bleiker 2025-06-02T07:07:08.643819Z

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.

Gregory Bleiker 2025-06-02T07:22:24.846139Z

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?

exitsandman 2025-06-02T07:57:39.625079Z

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).

Gregory Bleiker 2025-06-02T08:03:40.144899Z

@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")

walterl 2025-06-02T11:45:55.035309Z

> 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".

2025-06-02T17:13:23.436929Z

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.

VardriPoise 2025-06-01T18:31:51.359069Z

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?

VardriPoise 2025-06-01T18:32:39.539699Z

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?

p-himik 2025-06-01T18:33:30.544459Z

What do you mean by "provide the next form"?

VardriPoise 2025-06-01T18:34:15.059089Z

e.g.

(mymacro)
(def myid [x] x)
the return value of mymacro would be \backquote (def myid [x] x)

VardriPoise 2025-06-01T18:34:28.528529Z

I mean its macroexpansion

VardriPoise 2025-06-01T18:34:47.117259Z

this would shadow myid in normal execution

p-himik 2025-06-01T18:35:13.686099Z

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.

VardriPoise 2025-06-01T18:37:19.473199Z

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)

VardriPoise 2025-06-01T18:38:13.808489Z

it would be exclusively in a test-time/non-prod setting so I think this could possibly make it more acceptable (maybe?)

VardriPoise 2025-06-01T18:40:23.844599Z

especially if the macro has something like:

(if global-test-time-enabled-boolean `(def myid ...) nil)

p-himik 2025-06-01T18:41:06.984579Z

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.

VardriPoise 2025-06-01T18:42:12.389679Z

hm right, instrumentation as in specifically the clojure.spec.alpha utils or, instrumentation in a more general sense?

p-himik 2025-06-01T18:45:07.932729Z

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.

p-himik 2025-06-01T18:46:40.744439Z

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.

VardriPoise 2025-06-01T18:47:00.988909Z

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

👍 1
seancorfield 2025-06-01T19:10:03.116449Z

There are also libraries that add tracing, such as https://github.com/clojure/tools.trace

💯 1
VardriPoise 2025-06-01T20:48:37.217289Z

did not know of it, ty!

2025-06-02T00:44:51.023839Z

Cider also supports tracing by default: https://docs.cider.mx/cider/debugging/tracing.html

2
2025-06-02T00:50:34.864269Z

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.

💯 1
VardriPoise 2025-06-24T02:01:49.030269Z

I just now saw your replies, thanks a lot! I will look deeper into cider's tracing