fulcro

Kevin Olson 2024-09-20T18:26:41.037569Z

I'm using https://github.com/fulcrologic/statecharts (outside of fulcro) and I keep wanting to do something like:

(state
  (transition {:target (fn [env data] (:storedtarget data))})
)
Basically automatically go to a target whose id is determined by looking in working memory. I can think of a few reasons why that sort of thing is a bad idea (even it were legal) but I guess I'm just curious what others do. I presume something like using the choice helper, even if the list of targets/predicates is quite long? Really love statecharts btw...

Kevin Olson 2024-09-24T14:58:47.869439Z

Yeah Fig. 20 from the paper looks like one branch of my statechart. My eagerness to programmatically generate states and transitions based on the various "business" rules resulted in what the paper refers to as "the exponential blow-up in the number of states". So more like a state diagram than a statechart. What I thought was a simplification was maybe just me being a bit lazy/naive. At any rate, I think I have to abandon the tight coupling between rules and states. I am still curious if I'll need strongly-typed (to borrow a phrase) transitions - or if the things that are unique about a common transition (i.e. "tally vote") can just be embedded in the side effects that occur during the transition itself. Again - thanks for the help.

🎉 1
tony.kay 2024-09-20T18:50:45.374919Z

Your example is a little under-stated. You’re saying WHAT you want to do as opposed to the problem you’re trying to solve. It’s like saying “I want to use GOTO in my Clojure program, but it isn’t here”…one could talk about sequences, laziness, loop ,`doseq` , dotimes, etc. The fact that you want to use GOTO isn’t sufficient data to make a recommendation.

tony.kay 2024-09-20T18:51:56.974519Z

You’ve implied that you problem is that your “list of targets is quite long”, so perhaps your problem statement is “I’d like to compress my chart some”?

tony.kay 2024-09-20T18:53:17.703289Z

What I typically do is invent new node types, which in turn output the “mess of nodes” that I’d have to manually type. In this case that would probably turn out to be a macro

tony.kay 2024-09-20T18:53:30.684619Z

(but maybe not, actually)

tony.kay 2024-09-20T18:54:20.943869Z

but yeah, storing where you want to go as data in the machine is basically saying “I want to escape from the structure of statecharts and just write imperative code”

tony.kay 2024-09-20T18:55:41.285829Z

At that point, just emit “goto” transitions at the top of you chart for every possible destination, and then have actions that emit the corresponding “goto” event.

tony.kay 2024-09-20T18:55:56.509669Z

(A transition that does a raise)

tony.kay 2024-09-20T19:14:03.747669Z

However, the other thing that comes to mind is that you may be representing something with States that should actually just be data. I've done that mistake myself. Sometimes you just want a piece of data in the data model that represents something, which sort of sounds like a state, but shouldn't actually be represented as an official state in the state chart. In other words, sometimes data is just data

tony.kay 2024-09-20T19:15:14.107409Z

Ask yourself questions like: Do these states do something specific in transitions between each other that is specific to them being represented as a graph. In other words changing from State a to State b causes something different to happen than say changing from State c to State b. Do you need some code to run when entering or exiting one of these states? Are there rules governing the transition from state to state?

Kevin Olson 2024-09-20T22:10:43.505989Z

I appreciate the input, thank you. Yeah I should have been more clear, below is a bit more context - mostly just added in case it helps someone else down the road. The answer is "yes" to the last three questions you asked. I'm working on a system where it feels natural for there to be some commonly called event (call it :evt/common) but for it to target different states based on "how we got there".

Scenario 1 - Calling :evt/common in :state/a goes back to :state/0

Starting in      :state/0
:evt/goto-a  --> :state/a
:evt/common  --> :state/0

Scenario 2 - Calling :evt/common in :state/b goes back to :state/0

Starting in      :state/0
:evt/goto-b  --> :state/b
:evt/common  --> :state/0

Scenario 3 - Calling :evt/common in :state/b this way goes back to :state/a

Starting in      :state/0
:evt/goto-a  --> :state/a
:evt/goto-b  --> :state/b
:evt/common  --> :state/a
Of course in the 3rd scenario :state/b has to be something different, like :state/b-after-a or whatever. I really do want the same things to happen within the :evt/common transition in all scenarios fwiw. Maybe I'm just trying to avoid new states (I have 582 already), maybe I'm just not experienced enough with macros (or equiv) to ease the burden, or maybe I'm scared the statechart will get too big. Or more likely, as you say, I have states where I should just have functions and data.

Kevin Olson 2024-09-20T22:13:16.179639Z

FWIW I'm in the midst of building a system based on Robert's Rules of Order. I'm using the Fulcro/Pathom/Datomic stack (web/react-native) along with statecharts to help implement/model the rules themselves. The rules have various standard characteristics (precedence, is it debatable?, needs a second?, http://www.rulesonline.com/rror--02.htm) along with many pages of prose (in the official book) dedicated to corner cases per rule. I've had some pretty good success generating the states and transitions automatically based on those characteristics. So there are common events like "tally vote", "make motion", and "second". There is an interface in the UI that says "hey, given where you are, these are the events that are legal to do next". You can sort of picture the actions taken during a meeting, and the rules that guided you there, as a tree (which the UI shows too). When I'm struggling to implement something deep within the lifecycle of a complex motion I find the 30 years of my imperative mindset creeping in. Anyway, thanks for letting me talk through it "out loud".

Kevin Olson 2024-09-20T22:15:29.199679Z

I definitely can solve this round of challenges with auto-generating some more child states - just thinking through my options.

tony.kay 2024-09-20T23:25:14.161159Z

I don't know if these apply at all but if you considered the history nodes? Obviously I don't understand your problem well enough to know if that would help, but one common thing that happens is that you want to remember sort of a default or last used state. State chart support that concept directly. Have you read Harel's original paper?

tony.kay 2024-09-20T23:25:27.164299Z

I think it was written in the '80s. It's easy to find online in PDF form

Kevin Olson 2024-09-20T23:59:31.950709Z

Yeah I should take a closer look at history. I haven't read the paper, will do so this weekend - maybe that will help me think about it in a clearer way.