This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-04-18
Channels
- # babashka (12)
- # beginners (35)
- # biff (6)
- # calva (23)
- # cider (7)
- # clj-kondo (10)
- # cljs-dev (15)
- # clojure (81)
- # clojure-dev (2)
- # clojure-europe (13)
- # clojure-germany (1)
- # clojure-korea (2)
- # clojure-nl (1)
- # clojure-norway (19)
- # clojure-uk (7)
- # clojurescript (23)
- # core-typed (33)
- # cursive (7)
- # data-science (7)
- # datalevin (9)
- # hyperfiddle (1)
- # introduce-yourself (2)
- # malli (1)
- # matrix (17)
- # missionary (24)
- # music (1)
- # off-topic (15)
- # polylith (6)
- # reagent (10)
- # releases (5)
- # remote-jobs (1)
- # shadow-cljs (3)
- # squint (7)
- # xtdb (11)
- # yamlscript (6)
I’ve tried Claude a bit and it doesn’t seem as “current” as chatgpt. I tried it with photoshop javascript and it kept using an older previous generation api code. Even though a newer api has been out for years?
ps I love your continued shared elucidations (and humble epiphanies) of the nature of the value of matrix approach.
Heh-heh, thx Ryan! I was a running joke in the c.l.lisp community, RIP.
Just used it in anger on an app, this time fueled by the coarse reactivity of Supase/PG notify
. Went so well I will be beating the MX drum even worse. :rolling_on_the_floor_laughing:
Sorry Claude did not work for you. You know, all these tools are just fancy indexes, sometimes not as useful as a solid SO answer.
Say @hiskennyness, how do you debug the dependencies graph? I was thinking about visualizing it: https://clojurians.slack.com/archives/C02V9TL2G3V/p1713448194299159
In this case...
[{:id 1
:dependants #{2 3}
:dependencies #{4 5}
:status :clean}
.
.
.]
...I would have a Web/MX DIV with children for:
• a sub-div the thing itself, id=1 and its status
• a div, column or row, with a child for each dependent; and
• a div, col or row, for dependencies.
Or I would try SVG so I could draw arbitrary lines as dependencies or dependents. Much less cluttered.
Tbh, when I do think about doing this, I end up thinking about using GraphViz and figuring out how to drive that with MX internals data.From @U7RJTCH6J clj-graphviz works directly with graphviz's underlying c library. The hope is to provide tighter integration with the graphviz library and expose underlying features that are hard to access via the dot command line tool (like graph layout). Graphviz offers many options to tweak how graphs are rendered. It also offers graph layout without rendering. Exposing more of graphviz's functionality with a friendly clojure interface is a natural next step. https://github.com/phronmophobic/clj-graphviz?tab=readme-ov-file#related
I tried to provide relevant examples in the https://phronmophobic.github.io/clj-graphviz/. Happy to answer any questions if you try it!
Graph layout is already included in the latest release, but it's not very well documented. Let me if that's something you might be interested in. For example, you could use layout to get data for how nodes are arranged and create an interactive viewer in matrix.
@U7RJTCH6J it's mentioned in the original post but my data is in cljs. Do you think I can use graphviz from cljs?
Not directly as graphviz is written in C. In theory, you could compile the dependencies using emscripten, but that's not currently supported.
Funny you ask. I never think about the bigger DAG picture. In my experience, I just need to get each formula correct, in isolation. "The old saying is, take care of the pennies and the pounds will take care of themselves." On very rare occasions I create a cyclic dependency, but when those arise the runtime prints out the chain of dependencies in the runtime cycle, and I can figure out where my logic went wrong, or more likely where I had a dependency that was overbroad and not a true dependency. I have toyed with displaying the run-time graph just for fun, but I get bored quickly since it is kinda obvious and does not help me. Are you concerned about the size or density of your DAG? I guess after all these years I unconsciously avoid insane reactive formulations. Again, rather than viewing the DAG, I again recommend counting the nodes and dependencies per node. You can also count derivations of your homebrewed CSS.
I'm having some nodes recomputing when they're (in my mental model) shouldn't, and I want to figure out what triggers them.
Ugh, always a challenge. I have not used it in forever, but IIRC Matrix internals bind a *causation*
dynamic var which IIRC is a chain of causations leading up to a formula being kicked off.
Don't know your architecture, but wherever one property decides to trigger another property, before hand it adds itself to the causation chain. Sth like that.
Somewhat paraphrased:
(defn propagate-to-callers [c callers]
(when-not (empty? callers)
(let [causation (cons c *causation*)]
(with-integrity (:tell-dependents c)
(binding [*causation* causation]
(doseq [caller (seq callers)]
...notify caller....))))))
The curious local binding of causation is required because `with-integrity` may not run its body right away, so `*causation*` may not be valid by the time the code runs.
I also use my nested tracing hack to explore these things. That gives me one indented line per call to a state propagation function or two, then I scroll thru the output watching for the troublesome recomputation. If you figure out the problematic trigger scenario, and if it is not a no-brainer logic error, Matrix does have a couple of otpimization tricks you might want to emulate. Depends on what you find, so follow-up if needed when you have more details.
What optimizations? 😏 We love optimizations 😂
Optimizations:
• without-c-dependency
Runs its body, during which reactive values can be read without creating a dependency;
• unchanged-if
per cell override of =
for determining if a newly computed value is different from the prior value; and
• synapses
mid-formula computations that are like anonymous cells. These can be heavy hitters that throttle change by deciding not to propagate. You can do this the hard way just by creating a real cell that tries to absorb frequent change.
And we can always add new tricks!
Optimizations:
• without-c-dependency
Runs its body, during which reactive values can be read without creating a dependency;
• unchanged-if
per cell override of =
for determining if a newly computed value is different from the prior value; and
• synapses
mid-formula computations that are like anonymous cells. These can be heavy hitters that throttle change by deciding not to propagate. You can do this the hard way just by creating a real cell that tries to absorb frequent change.
And we can always add new tricks!