This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-12-29
Channels
- # aleph (1)
- # announcements (5)
- # beginners (21)
- # cider (4)
- # clojars (1)
- # clojure (39)
- # clojure-europe (5)
- # clojure-norway (133)
- # clojurescript (5)
- # datomic (27)
- # exercism (2)
- # gratitude (4)
- # humbleui (21)
- # hyperfiddle (10)
- # integrant (16)
- # introduce-yourself (1)
- # lsp (17)
- # matrix (1)
- # nbb (10)
- # overtone (5)
- # polylith (21)
- # re-frame (6)
- # squint (3)
- # tools-deps (22)
- # yamlscript (102)
Hi all! Thought I'd share a project I've been working on and off during the last year https://github.com/migalmoreno/tubo (Not sure if this is the right channel for self-promotion/contributions). It essentially aims at being a port of Newpipe, a front end to various streaming services, but for the web. It leverages the NewpipeExtractor Java library to gather the data, exposes it via a simple REST API and uses re-frame for the front-end SPA. It's my first time using Clojure(Script) in a personal project so any ideas/comments are welcome!
Cool! #C06MAR553 is for new projects and big releases (major features, been a long time since last release, etc), and #C015AL9QYH1 is for smaller releases and minor updates
Thanks for the heads up! I'll post it there then
This may be an XY problem, but I want to be able to have circular references in a namespace without forward declaring vars, so that I can take advantage of direct linking when AOT compiling. My use case involves declaring Reitit route data referencing a function that will perform reverse routing with such data. The reason this function needs reverse routing is because I want a single source of truth for generating redirect URLs — my route data. But the design of the Reitit library is such that the data must reference the function, so what I want is a circular reference. I can easily do this by simply declare
-ing the function when I define my routes, but from what I understand, this makes direct linking of vars impossible. Should I just live with this fact?
I have also looked into replacing this handlers with a multi-method dispatching on the :request-method
of a request map, but this hinders the ability to use default routers, since Reitit will end up calling the multimethod for all HTTP request methods. For this reason, I have decided against multi-methods.

OK typing this out made me realize what I really want is some Ring middleware that passes the router down to handlers. This made me look into Reitit documentation to see if there was something like this. Lo and behold, what I really want is this. https://cljdoc.org/d/metosin/reitit/0.6.0/doc/ring/reverse-routing#reverse-routing-with-ring
Hi, does anyone have any insights into why partitioning a map into {}
results in the same map being returned? I initially expected it to fail because partition typically returns a seq over a seq of pairs, rather than a seq over the pairs themselves.
;; partition over a map comes back a seq over a seq of the map pair
user> (partition 1 {:a 1})
(([:a 1]))
;; and it unexpectedly to me gives back the same map when `into {}`
user> (into {} (partition 1 {:a 1}))
{:a 1}
;; if it is a vector over a vector of the same pair though fails (as expected)
user> (into {} [[[:a 1]]])
Execution error (IllegalArgumentException) at user/eval8353 (REPL:174).
Vector arg to map conj must be a pair
;; a vector over the same pair works as expected
user> (into {} [ [:a 1] ])
{:a 1}
;; a seq over a seq of the same pair
user> (seq [ (seq [ [:a 1] ] ) ])
(([:a 1]))
;; the same initial example with seq fails, so why is partition works at all?
user> (into {} (seq [ (seq [ [:a 1] ] ) ]))
Execution error (ClassCastException) at (REPL:1).
into
is just a reduce
with conj
.
conj
'ing a kv-pair onto a map is equivalent to assoc
'ing those k-v.
(into {} [[[:a 1]]])
fails because you have an extra level of nesting. Remove one pair of [...]
and it'll work just fine, as you have demonstrated yourself.
Oh, my bad - didn't notice that initially there's an extra nesting as well.
It works because conj
'ing a sequence onto a map works if that sequence is a sequence of map entries specifically (so a 2-item vector won't work).
You can see the implementation here: https://github.com/clojure/clojure/blob/56d37996b18df811c20f391c840e7fd26ed2f58d/src/jvm/clojure/lang/APersistentMap.java#L27-L49
why isn't the last example working though? it's the same as the partition collection, a seq over a seq over same pair
The partition function returns a sequence of partitions, where each partition has only proper map entries - instances of the Map.Entry
class.
The last example creates tuples - they are not instances of that class.
Right, thanks, I'd say this appears to be an implementation coincident rather than a design feature
user> (seq [ (seq [(clojure.lang.MapEntry/create :a 1)])])
(([:a 1]))
user> (into {} (seq [ (seq [(clojure.lang.MapEntry/create :a 1)])]))
{:a 1}
Can you suggest some good resources to get started with non-trivial macros (DSLs)? It feels like I'm hitting some barrier, which I need to overcome first to achieve anything meaningful...
Study this code: https://github.com/clyfe/clara-eav/blob/master/src/clara_eav/dsl.clj#L123-L126
I find that a lot of people skip the first step, which is thinking about how to do stuff with data and functions. Do that first (it will be verbose), then write the macros to transform syntax into that
Data and semantics first, syntax last
This is a super old talk but still an extremely good one in this area (and Christophe is a master at this) https://youtu.be/3yvrs9S0RIw?feature=shared
@U2FRKM4TW Writing non trivial macros is a great use case for clojure.spec (conform, transform, unform), hence the example.
Isn't that quite limiting? The transform function would only be able to return something that conform
with that spec can return, otherwise the contract of unform
is broken, even if things end up working just fine.
There's a great deal of wisdom in Christophe's words, but I've got an actual assignment to make a macro for an already defined DSL :rolling_on_the_floor_laughing:
But what is the problem? If it's with macros, we're happy to help if you provide some specifics. If it's with transforming some particular DSL into something else - same thing. But "non-trivial macros for DSL" without any details isn't that useful, even as a grounds for recommending learning resources.
Fair. I'm just hitting compiler errors all the time, so I thought I'm doing something completely wrong. Looking at some examples shared here, it's not that different, so there must be some small but a key detail I'm missing. I borrowed an (old) book from a friend to help myself. If that won't suffice, I'll ask about specific errors I'm getting. Thank you!
If there's an example that fails that's small enough, sharing it won't hurt. Might get you up to speed much faster than reading a whole book (although the latter also won't hurt if you're not in a hurry).
Hello! I am trying to apply https://clojure.org/guides/dev_startup_time, which suggests
> The compile
function takes a namespace symbol and compiles that namespace and all the namespaces it requires into *compile-path*
but in my case it only compiles the given namespace itself, and none of its dependencies. I.e. inside my compile-path, which is target/classes/, I only see my/ns//*.class. How is that possible? What am I missing? Clojure 1.11.0 🙏
Compilation works as a side effect of loading code, so if you have already loaded stuff you can get weird behavior when trying to compile
> Oh, likely you already loaded everything
> Compilation works as a side effect of loading code
Oh, that must be it, thanks a lot! That wasn’t really clear to me 😅 Then I will try to (require <ns> :reload-all)
workaround…
Hm, I still do something wrong. I have tried
(do (compile 'user)
(binding [*compile-files* true] (require 'user :reload-all))
(compile 'user))
yet still nothing is compiled… (my user.clj is on the classpath, and loads many namespaces)
(I believe the compile
calls are unnecessary, setting the dyn. var. should be enough)Ah, I got it working now, after I replaced user
with my init ns: (binding [*compile-files* true] (require '
I would not trust compiled from reloaded, it is very easy to end up class files written to disk that depend on the previously compiled code that only exists in memory
Ok, so the best approach then is to have an explicit compile process / step , instead of trying to trigger it from the REPL, right?