This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-17
Channels
- # announcements (7)
- # beginners (9)
- # calva (17)
- # clj-kondo (11)
- # clojure (68)
- # clojure-austin (2)
- # clojure-bay-area (3)
- # clojure-europe (19)
- # clojure-gamedev (10)
- # clojure-nl (1)
- # clojure-norway (73)
- # clojure-spec (5)
- # clojure-uk (5)
- # clojuredesign-podcast (6)
- # clojurescript (65)
- # community-development (28)
- # conjure (1)
- # datahike (34)
- # datomic (36)
- # emacs (11)
- # funcool (1)
- # helix (13)
- # honeysql (36)
- # hyperfiddle (15)
- # jobs (1)
- # jobs-discuss (4)
- # malli (13)
- # nbb (21)
- # off-topic (51)
- # practicalli (20)
- # reitit (1)
- # releases (1)
- # ring (4)
- # squint (1)
- # tools-deps (14)
- # transit (8)
I have a tight loop/recur doing graphics rendering... It seems like this loop blocks evals from my editor (emacs/cider). When the loop exits, the evals go through. What's the proper way to workaround this so I can eval functions called in the loop?
You have to start your loop in another thread. The easiest way is to do (future (my-background-code ...))
Wait, I'm not sure I understood this part > so I can eval functions called in the loop You want to be able to interact with CIDER while your rendering code runs in the background, right?
Here's a simple example
(def state (atom true))
(defn do-stuff [a b ]
(+ a b))
#_(defn do-stuff [a b ]
(prn "doing stuff"))
(defn test-loop []
(prn "started")
(while @state
(do-stuff 1 2))
(prn "stopped"))
(comment
(future (test-loop)) ; to start the loop
(reset! state false) ; to stop the loop
;;
)
I added the (future...)
as you recommended. I want to be able to swap the do-stuff
function and have it reflected in the loop.
But with the code above if I 1) start the loop, 2) comment out the first do-stuff
and uncomment the second 3) eval the new do-stuff
, I don't see any "doing stuff"
printedI literally repeated what you did in the REPL and I see "doing stuff"
being printed.
Maybe it's the printlns from the other threads that are being swallowed by CIDER, however I don't think it should happen
Did this in CIDER, works for me
(def state (atom true))
(defn do-stuff [a b]
(+ a b))
(defn test-loop []
(prn "started")
(while @state
(Thread/sleep 1000)
(do-stuff 1 2))
(prn "stopped"))
(future (test-loop))
(defn do-stuff [a b]
(prn "doing stuff" a b)
(+ a b))
When I do exactly that, the eval of the second do-stuff
works and If i eval (do-stuff 10 10)
I see the "doing stuff 10 10" output, but not the output that the loop should be generating
i made a minimal deps.edn and tried it there, and it's working.. so something is wrong with my projects env I suppose
I bet that the output streams got messed up. That is the easier thing to break than the live recompilation functionality
You can replace printlns with another atom (say, a counter) that you would start incrementing in a redefined do-stuff
. Just to reassure yourself
thanks for helping me trouble shoot this @U06PNK4HG I should have enough now to narrow down what the issue is.
Aha I was running the prod profile not the dev profile and prod has direct linking enabled.. that would do it :)
Hmmm, direct linking popped into my mind but I didn't voice it aloud. Good that you've found the culprit!
cider-debug
can be a very useful tool to see what an iterative piece of code is doing. It automatically adds breakpoints and shows intermediate values as it evaluates each line of code.
Hello.
Let's say I've got transducer (map inc)
. Is this possible to somehow wrap around that full transducer, so it will have effect like (map (something inc))
?
For example, I've got (map (fn [{:keys [args]}] {:args (inc args)}))
. Is this possible to somehow wrap it the other way around, so it will be
?
Basically, I've got a vector of transducers [(map something) (map something)]
- a clojure.core.async
pipeline and I'd like to automatically wrap every one of these so I can carry something extra between (a OpenTracing
span created in the first step of the pipeline) without having to modify each of the inner functions. In other words, I'd like to add onion layer to carry the span around channels.
Hope it is clear enough 🙂 Thanks for any advice!
I'm not sure if I'm understanding the question correctly, but you can compose transducers, so if you wanted to square each numbers before inc'ing it, for example:
(let [inc-xf (map inc)
square-xf (map #(* % %))]
(transduce (comp square-xf inc-xf) conj [1 2 3]))
=> [2 5 10]
i think it’s changing the shape of what’s going through. the classic refactor from a single arg to a map so you can pass more things through
i read it as starting here
(let [x1 (map inc)
x2 (map inc)]
(transduce (comp x1 x2) conj [] (range 3)))
[2 3 4]
and wanting to adjust x1
and x2
to handle a new map shape like
(let [x1 (map inc)
x2 (map inc)]
(transduce (comp x1 x2) conj [] [{:x 1} {:x 2} {:x 3}]))
OK, let's have a look at this:
;; basic transducers
(def transducers-1
[(map #(+ % 1))
(map #(- % 1))])
(into []
(apply comp transducers-1)
[1 2 3])
(def add-span
(map (fn [x]
{:span "some-span"
:args x})))
(def init-span (map (fn [x] {:span "some-span" :args x})))
(def close-span (map (fn [x] (:args x))))
;; explicit case
(defn wrap-span [f]
(fn [{:keys [span args]}]
(log/info args)
{:span span
:args (f args)}))
(def transducers-2
[(map (wrap-span #(+ % 1)))
(map (wrap-span #(- % 1)))])
(into []
(apply comp (concat [init-span]
transducers-2
[close-span]))
[1 2 3])
;; What I'm looking for is function `wrap-with-spans` to :
(into []
(apply comp (concat [init-span]
(wrap-with-spans transducers-1)
[close-span])))
I'm looking if wrap-with-spans
function is possible that unwraps arguments for transducer from map, applies it to transducer and packs it back.
But actually that's only part of the story, since that's for https://github.com/alvinfrancis/opentracing-clj
so, I think (not a transducer expert) that it'd be necessary to turn wrap-span into a transducer so it can be comped onto another transducer
So it's more like
(defn wrap-span [f]
(fn [{:keys [span args]}]
(log/info args)
(tracing/with-span [_ {:from span}]
{:span span
:args (f args)})))
so each transducer does not have a way of inspecting transducers which occur before it. Once you combine transducers with comp
they become fully opaque.
That said, it would be entirely possible to make a function which takes a transducer and applies it only to a wrapped element in a map.
(defn under-key
[k xf]
(let [inner-rf (xf #(assoc %1 k %2))]
(fn [rf]
(completing
(fn [acc elt]
(rf acc (inner-rf elt (get elt k))))))))
(sequence
(comp (map #(-> {:hello %}))
(map #(assoc % :buz :quux))
(under-key :hello (comp (map inc)
(map -)))
(map #(assoc % :bar :baz)))
(range 3))
;; => ({:hello -1, :buz :quux, :bar :baz}
{:hello -2, :buz :quux, :bar :baz}
{:hello -3, :buz :quux, :bar :baz})
For your example case of wrapping a span, you could also add logging or similar to the under-key
transducer, although if you wanted logging for each individual step you would need to use it multiple times, as again, you can't peek into what's happened once comp is called. You could introduce your own comp
function that would add in special things around each transducer though, much like what I have listed here.
With my under-key
from above you could implement your wrap something like this:
(defn wrapping-comp
[span-name & funs]
(comp (map #(-> {:args % :span span-name}))
(reduce comp (map (partial under-key :args) funs))
(map #(-> % :args))))
you'd want to apply some function over funs
before the under-key
in order to add your logging and such
but this would do it
I noticed a library that clj-kondo is confused about since the lib has a var that ends with .
, so you call it as (py. ...)
- clj-kondo thinks this is a constructor rather than a var and therefore something doesn't work as expected.
Is this even a valid var name in Clojure? I don't mean "does it work" but "is it supported"
user=> (let [f. (fn [x] x)] (apply f. [1]))
Syntax error (ClassFormatError) compiling fn* at (REPL:1:1).
Illegal field name "f." in class user$eval149
user=> (def f. (fn [x] x))
#'user/f.
user=> (apply f. [1])
Syntax error (ClassNotFoundException) compiling at (REPL:1:1).
f.
user=>
so you can indeed def a function with a name like f.
but you cannot let bind such a name, and calling the function is tricky
This is a some code undergoing further change in 1.12 with qualified instance member symbols, although I’m not sure that makes it worse
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6977 does the macro expansion before the dot form rewrites
I guess "Symbols beginning or ending with '.' are reserved by Clojure." from the Reader spec is enough to say: just don't do it
The reader page says “Symbols beginning or ending with '.' are reserved by Clojure.”
And indeed we are expanding both of those cases in 1.12 :)