This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-06-22
Channels
- # announcements (8)
- # architecture (1)
- # beginners (49)
- # calva (7)
- # cljdoc (7)
- # cljs-dev (4)
- # clojure (44)
- # clojure-italy (1)
- # clojure-spec (12)
- # clojurescript (88)
- # community-development (2)
- # cursive (8)
- # datomic (16)
- # fulcro (15)
- # immutant (3)
- # joker (10)
- # keechma (4)
- # lambdaisland (1)
- # luminus (7)
- # pathom (1)
- # qa (2)
- # re-frame (11)
- # reitit (8)
- # remote-jobs (1)
- # rewrite-clj (10)
- # shadow-cljs (1)
- # slack-help (2)
- # sql (1)
- # tools-deps (2)
- # vim (4)
- # xtdb (3)
does anyone know how is https://github.com/CoNarrative/precept going? cc @alex-dixon (I hope you are the right Alex Dixon)
Are you using precept?
Great success I hope 😊
I reached sort of local dead end with state machines (state charts), which leads me towards datalog/rule-based-systems (clara?), which is kinda what precept is, so I am wondering how are things there :)
Pretty good I think but I’m just me. 🙂 There’s a couple of examples that should be fairly quick and painless to run. I’d recommend starting there and see what you think
@U051HUZLD What are examples of state machines in Clojure(Script)? And what is your experience with them?
I wrote my own, which can handle widely branched and deeply nested state trees. but state trees turned out to be inherently unusable as a thing to build and manage as a user.
A bit simpler lib is https://github.com/samroberton/bureaucracy it supports machines nesting and composition, but has a fundamental "UX" limitation – you cannot go from state of one machine to state in another in a single go. E.g. on submit button click show another page. To represent this – you have to write an unobvious chain of state events and hops, which defeats the whole purpose, for me.
anything else – is either hello-world grade libs, which are 1 trivial function and not useful at all, or for very low level machines, like https://github.com/ztellman/automat, and require extra (mental) level of wiring to UI code. (but there is a non zero chance I just did not get it)
there is also https://github.com/candera/causatum but it is for a bit different purposes, which, again, does not match 1-to-1 to UI development (my main goal with state machines)
I’m curious if xstate solves any of these UX problems: https://github.com/davidkpiano/xstate
not sure how to judge that since I haven’t tried out state machines at all yet, but am v curious since some people seem to yell from the rooftops about them
the thing with state machines/charts for web dev/UI – you are up against the most convenient and inline way to do things. And comparing to just "hacking it" – benefits are so far away, it is not compelling at all, even if you are the one yelling from the rooftop. However, I believe it is a UX issue and lib API design, not a state machine approach issue.
yeah when I have watched people program directly with state machine APIs / data representations, it looked super verbose and indirect
seems like it would be better as a target for either compilation (DSL) or the domain model of some UI
since AFAICT the best parts of state machines / charts are visualization and consistency
the ultimate underlying issue is, I think: if you are trying to put graph in a tree – you are gonna have a bad time
we don't, actually, write it as a tree. and this is what you are up against as a FSM lib designer/user:
you define react component (or any function), and then use it in 5 places. this is graph, and it is essentially what you do, without any need to re-adapt to any new "style/approach/paradigm"
but since it is so close to everything else – state gets spread all over the place. because it is convenient to write it this way. you don't need to think to do that. and you have to think to not do it this way
inline is like "cheap fast food on your daily rout" vs. "expensive farmers market 50 miles away twice per month on tuesdays", convenience and willpower-cost wise
yeah, I think my (half-baked, inuition-based) thought matches what you’re saying. my waxing take on a Saturday afternoon is: when we write code, we write it as a tree. when we need to do graph-like things (like use a thing we created elsewhere, 5 times) we place references in the code, because code is represented as 2D text that can only get wider or deeper, not loop around or traverse to some other location directly. React elevates these references to first-class constructs (functions) and covers more than just the DOM but also state, effects, etc. to allow us to map this graph to our tree-like code like we’ve been taught. Hooks also follows this same strategy. Current state charts has to be embedded within the React graph and cannot be composed like the rest of the graph (it’s not first class), so you end up with a graph-within-a-graph, which it sounds like to tiny human brains, just isn’t worth the complexity cost of that.
I'll give you an example of a problem, @U4YGF4NGM https://xstate.js.org/docs/#parallel-state-machines here there is a description of bold/italic/list machine. never mind italic/bold are more verbose than just booleans in the map. but imagine, if you want to keep all the state in the same place (uber-state-machine), how will you attach example machine to the actual text? is it a copy of a machine per character (almost what draft.js does) or word, or is it something more complicated and way harder to reason about?
yeah, I thought about "extracting" state graph from, say, react, or just any clojure code. and this might be the way to go, actually. you write your daily code, but mark state bits with something (e.g. reader tags). and there is just a function, which renders you the mess you wrote in a repl
yep, I think the key is to follow the example React has set: make things locally reasonable / writeable but first-class and composeable
it’s not clear to me what the primary method of composition would be for a state chart
but, I think, easier approach would be rule engines + datalog. it is a shame clara has such shitty dsl out the box
well, state charts (and uml for that matter) – is just a visual vocabulary to representing things. it does not impose any rules of execution at all.
so the easiest (for dev) approach is to "add facts/constraints as you discover them, and let engine figure out output", like datomic queries
it is just datomic/datascript are too databasy, and need some appealing packaging for UI development: few shortcuts and convenient oneliners to get adoption going.
on the other hand, if you try to build and balance state graph/tree by hand: each new fact/state/transition will make you rebalance it by hand again. to know how that feels - just try to use any diagraming tool iteratively
Yeah I've been playing with some Hooks for Datascript. Been thinking about ways to declare schema, pull data into local state then transact
Unfortunately Datascript is pretty light on constraints but maybe that's a good thing
Where do FRP systems like Javelin/Hoplon stand in all this?
You mean 1000 javelin cells?
Subscriptions can also be managed by other tools like Keechma or re-frame.
+ it basically prevents you to be able to get entire state in a single "place", e.g. to persist. also, if the only api you get is full of macros - it better be worth it.
it seems to me, rum
solves this in a way leaner way. I'm not even mentioning "raw" add-watch (partly because javelin might actually offer something useful, and I just don't have any experience with it)
well, hoplon has this on its home page:
(button :click #(dosync
(swap! todo-items conj @new-item)
(reset! new-item ""))
So, basically not having state in single place increases complexity. Right?
I like Rum's idea of mixins.
increased amount of state increases complexity. having it in different places limit your option and make it harder to deal with/reason about
Fulcro solves the issue of state and data fetching(client/server communications) in elegant way.
I think that having state all in one place isn’t without it’s tradeoffs, tradeoffs which we’re not very good at measuring yet
it can literally increase complexity (in the Hickeyian way) by increasing the number of components that can subscribe ad-hoc to any value, making it difficult to change without additional machinery
there are also considerations like performance that end up increasing the total complexity of the system
@U051HUZLD Any thoughts on Precept or haven’t had time to try yet?
@alex-dixon did not run it yet, no.
I am interested in idea though (an API), and, frankly, amount of clojure.core/last
and butlast
in source worries me
@U051HUZLD PRs accepted 🙂 Worried about correctness or perf or…?
@alex-dixon perf (a bunch of functions I saw had several lazy seqs instead of single desctructuring, where it is obvious, that input is short), but it is waaay to early for me to either complain, claim anything, or send PRs, so disregard
e.g. here https://github.com/CoNarrative/precept/blob/1b2b23951e66817ccf24ca7711db938256781cc2/src/cljc/precept/serialize/facts.cljc#L8-L10
you scan all xs to bind last one, and then scan all of them again to drop it. Sure, it is namespace string, which is like ~1-7 elements long, but makes me want to read the rest of the codebase, just in case.
alternatively, since clojure.string/split returns persistent vector, you could just pop and peek for O(1).
however, sending pop/peek PR would be somewhat useless, since this function seems to try to achieve something very similar to cljs.core/demunge
:
cljs.user=> (cljs.core/demunge "foo.bar$baz")
"foo.bar/baz"
but, since I am not sure w/o inspecting all the call sites – I would not send demunge PR either @U051HUZLD Thanks for taking the time…that’s really helpful. I think fn->map
is only used for the dev tools. Recently I’ve been spending way too much time working on EDN serialization/deserialization for Rust so I should apply some of what I’ve learned from that here
I’m not disregarding. You’re right 🙂
yeah, that's what I'm saying: without much project-context loaded – any such PR is likely to be just nitpicking and waste of both ours time
I’m hosting a Clojure-backend, Clojurescript-frontend app on Heroku and everytime I refresh the page, the Clojurescript code is recompiling 😮
project.clj
with recommended :uberjar
profile: https://github.com/pianostringquartet/landschaften/blob/master/project.clj#L76
The heroku deploy appears to compile the cljs:
remote: Use clj -h for help.
remote: -----> Using cached Leiningen 2.8.3
remote: Writing: lein script
remote: -----> Building with Leiningen
remote: Running: lein uberjar
remote: Downloading Leiningen to /app/.lein/self-installs/leiningen-2.8.3-standalone.jar now...
...
...
remote: Compiling ClojureScript...
remote: Compiling ["target/cljsbuild/public/js/app.js"] from ["src/cljc" "src/cljs" "env/prod/cljs"]...
remote: Successfully compiled ["target/cljsbuild/public/js/app.js"] in 120.311 seconds.
remote: Created /tmp/build_a95d6139840adffffa725a79128a47dd/target/uberjar/landschaften-0.1.0-SNAPSHOT.jar
remote: Created /tmp/build_a95d6139840adffffa725a79128a47dd/target/uberjar/landschaften.jar
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 142.1M
remote: -----> Launching...
remote: Released v12
remote: deployed to Heroku
remote:
remote: Verifying deploy... done.
I see that you have an init!
defn in your core.cljs
, but it’s not exported and not called in your home.html
(which I assume is rendering the page)
I think the fix is to:
1. add :export
metadata to your init!
defn so that the name doesn’t get munged when advanced optimizations occurs:
(defn ^:export init! ...)
2. In your home.html
(and anywhere else where, after a full page load, you want to start your app), add a call after loading the app.js
file:
<script>
landschaften.core.init_BANG_();
</script>
which will start your app on page load after loading the JS fileHmmm… I’ve added landschaften.core.init_BANG_()
to my home.html
(the rendering page):
https://github.com/pianostringquartet/landschaften/blob/master/resources/templates/home.html#L51
… and the ^:export
metadata to init!
:
https://github.com/pianostringquartet/landschaften/blob/master/src/cljs/landschaften/core.cljs#L93
Unfortunately the ‘recompile on refresh’ behavior persists, visible here: https://landschaften.herokuapp.com/
you might consider changing the page in home.html
to display something other than that text. It’s display whatever is in home.html
until the app.js
file is done loading, then executes the init!
function
In this case, the app.js
is a bit hefty (2.3mb) so it takes a few seconds to load and start up
ah, okay; I was hoping to eliminate that text itself; I had assumed it was an issue with the js not yet being compiled hehe XD
Hi everyone! I'm having a newby problem, hope someone has mercy. I'm running figwheel through CIDER and also a separate ring-server. I'm trying to send an API-request to my ring but firefox informs me this is not in compliance with CORS-policy, which as far as I understand is because figwheel uses its own ring to serve up the page and connect to it. Now I use ring-cors to set :access-control-allow-origins to #".*" and :access-control-allow-methods to :get, but this does nothing so far. Also I tried disabling strict_origin_policy in firefox which felt quite wrong but also did nothing to help. So I must be misunderstanding something rather basic here.