Live data from Hacker News

FSL: A programming language to make complex finite state machines easy to create

fsl.tools

61–70 of 74 posts

Re: FSL: A programming language to make complex finite state machines easy to create

#61
post #55

Earlier quoted context omitted.

> I feel like we don’t need a novel language for this. Well, there's like 50 others, many of whom are in heavy use in industry, so, I guess I feel like a lot of people think this is useful. . > I feel like Erlang is already a great language — almost a DSL — for “making complex finite-state machines easy to create.” Erlang is almost my favorite language. I've tried using both of its finite state machine libraries. I d…

> I've tried using both of its finite state machine libraries. I'm not talking about gen_fsm or gen_statem — note how I said "without OTP" above. I'm talking about writing Erlang the way it was originally conceived before proc_lib existed — where each process has a module that's exclusively responsible for its own receive loop, rather than being a delegate module for a generic receive-loop manager framework (proc_lib…

> note how I said "without OTP" above

I apologize for overlooking this

.

> You don't call into arbitrary slap-dash non-formalized libraries

Respectfully, no, it sounds like you write them yourself, instead

.

> > FSMs are a great example. You either need to reach outside the Beam VM with `hipe_bifs:array` or you need to copy the entire machine state every time you want to mutate it. > > Why are you mutating something outside the FSM from within the FSM?

I'm not. I'm talking about the expense of the action of the FSM mutating itself.

.

> The point of an FSM is to reduce the "power" of reasoning needed to prove things about the abstract machine

I apologize, but you and I have strongly contrasting opinions here.

The rest of you trying to teach me what an FSM does is noted. Thank you for your time

.

> I think we might be talking about very different things here but both calling them "FSMs." I'm talking about how Erlang's native syntax is really good at expressing https://en.wikipedia.org/wiki/Deterministic_finite_automaton (like non-backtracking regexps) succinctly. What are you talking about?

My library, and finite state machines, which are the superfamily containing DFA and a great many other things. DFA is not a common interpretation of the phrase FSM; usually that phrase means a Mealy machine or a Moore machine, or maybe a Harel machine.

I think you're spending more time attempting to force this library to implement some computer science term you're familiar with than is warranted. JSSM doesn't fit any of those labels well.

DFAs are generally a small group of functions meant for parsing strings. JSSM isn't even superficially similar to a DFA, and most state machines in practice aren't implemented that way in my personal experience.

Re: FSL: A programming language to make complex finite state machines easy to create

#62
post #42

Very interesting project. Sorry for my ignorance though, where in the industry something like this might be useful?

State machines are a great way to control defects by producing states which are only able to mutate in certain specific pre-defined ways

The defacto example is usually a traffic light. Green is permitted to transition to yellow, but never to red; a state machine makes a bug of that form impossible

Obviously, it's nominally used for more complex stuff, but in general, all of your appliances are state machines. Your microwave especially.

Re: FSL: A programming language to make complex finite state machines easy to create

#63
post #43

Since I'm here, any tool recommendations for visualizing state machines, and state charts in particular? XState's [1] is ok but only works on the web and offers to export, and I found its layout algorithm a bit sub-par. Writing graphviz code by hand, or using google draw/draw.io/... gets painful very quickly. [1]: https://xstate.js.org/viz/

PlantUML is quite handy and text input based. I'm embedding the text state chart directly in the source code as comment to have it under version control.

https://plantuml.com/en/state-diagram

Re: FSL: A programming language to make complex finite state machines easy to create

#64
post #43

Since I'm here, any tool recommendations for visualizing state machines, and state charts in particular? XState's [1] is ok but only works on the web and offers to export, and I found its layout algorithm a bit sub-par. Writing graphviz code by hand, or using google draw/draw.io/... gets painful very quickly. [1]: https://xstate.js.org/viz/

JSSM has JSSM-viz. https://github.com/StoneCypher/jssm-viz If you just want one to use, rather than to embed in your own software, The thing everyone's calling a live editor is actually the JSSM-viz demo. You can use that https://stonecypher.github.io/jssm-viz-demo/graph_explorer.h... It's kept outside of the main repo because, like xstate's, it's built on a transcompile of graphviz called viz.js, which is made with…

The problem is that this uses your new custom language which is not yet documented. I had seen this, I asked for alternatives because it doesn't seem to be an option yet.

The examples in your README also seem very limited, with no guards/actions/recursion/parallelism (correct me if I'm wrong). The last two I can do without but it seems overly simplistic as of now.

Re: FSL: A programming language to make complex finite state machines easy to create

#65
post #26

I feel like we don’t need a novel language for this. There’s already a pretty-well-known language that’s almost a DSL for “making complex finite-state machines easy to create”: Erlang. I know that sounds wacky, so let me pitch you on that idea :) In ‘primitive’ Erlang (i.e. Erlang without OTP), each FSM state is just a function, that can contain its own event loop (`receive` statement) to accept input, and then can t…

I do not know anything about erlang, but I’m intrigued about your proposal. Could you make a github repo with an example project implementing your solution?

Pattern matched state machines are how Prolog, one of Erlang's parent languages, is expected to work. This is how they implement horn clauses.

I can't speak for parent poster, but, I imagine that they mean something like this (which is also almost valid prolog, and mozart/oz, and some others:)

  -module(pattern_match_tl_fsm).
  -export([ next/1, disable/1, enable/1, enabled/1, may_pass/1, create/0 ]).
  
  next(red)    -> green;
  next(green)  -> yellow;   % allow the lack of a match to throw for off; there is 
  next(yellow) -> red.      % no next state for a light that's turned off
  
  enable(off) -> red.       % allow the lack of a match to throw for every color;
                            % only lights turned off may be turned on
  disable(red)    -> off;
  disable(green)  -> off;   % allow the lack of a match to throw for off; cannot 
  disable(yellow) -> off.   % disable if already disabled
  
  enabled(off) -> false;
  enabled(_)   -> true.
  
  may_pass(green)  -> true;
  may_pass(yellow) -> careful;
  may_pass(red)    -> false;
  may_pass(off)    -> careful.
  
  create() -> off.
And then you can do stuff like

  TrafficLight = pattern_match_tl_fsm:create(),
  TurnedOn     = pattern_match_tl_fsm:enable(TrafficLight),
  Step2        = pattern_match_tl_fsm:next(TurnedOn),
  etc
For very simple things this is probably a great choice, and OP is correct to suggest that this is very debuggable, especially if those states are tagged tuples instead of lazy-example atoms. However, the rate at which it doesn't scale is magnificent. By contrast:

  import { sm } from 'jssm';
  
  const make_light = () => 
    sm`off -> red => green => yellow => red; [red yellow green] ~> off;`,
  
  const safety     = { red: false, green: true, yellow: 'careful', off: 'careful' },
        enabled    = light => light.state() !== 'off',
        may_pass   = light => safety[light.state()];
  
  export { make_light, enabled, may_pass };
And that gives you basically the same interface for way less code.

Of course, bringing in an interpreter and/or a compiler isn't zero cost, so if you only have a couple of the straight module ones, the first notation honestly can be a pretty good approach, and given Erlang's module compositional nature, it's frequent to have things that in other languages would be unrealistically simple. By example, the TCP/IP state machine is 11 states and 19 edges, and in my opinion would make sense in the first notation as its own standalone module in erlang. I believe that parent post has a solid point.

The reason one tool hasn't universally won is that there isn't a best way to do this, style of thing. Trade-offs.

Still, with the sm`` notation, I find that I very frequently one-liner state machines with Also, when you start thinking about larger state machines, which sometimes have 50 states and 200 transitions, it is my opinion that that they grow at such different rates can quickly become important. When I say the TCP machine with 11 and 19 makes sense as a standalone, to me, that's getting not too far from the upper limit of where I'd think spelling it out manually was smart. (Still, to be fair, most FSMs are simple, rather than complex, so that's not all that harsh of a cutting criterion in the balance.) Even when hyper-dense, my opinion is that the sm`` arrow notation can easily carry 10x the structure on-screen and be comfortably readable than the typical datastructure based approach.

For me, the `jssm` chain is modifying how I think about code in some subtle ways, and that makes me feel like there might be actual value there. I hope you'll give it a shot and tell me whether or not you agree.

HTH

Re: FSL: A programming language to make complex finite state machines easy to create

#66

Very cool. I looked through jssm but get the sense that fsl or jssm might be adapted so that it can be used to declaratively generate an FSM for any language? I wish my colleagues knew what an FSM was and how to create one. Getting tired of seeing 400 nested IF statements sprinkled across 10 classes. Something that makes it easy to create an FSM declaratively for any language might help raise awareness and spur adopt…

Yes. ♥ Target compilers for languages and other FSM libraries are a core goal, and I believe this is probably the single most important thing my language needs (comparables in portable external hooks and user-defined state datatypes.) I want the frontend and backend (and the database and the PaaS and the orbital weapons platform and the barbeque) to run the same machine, even when they aren't the same language.

A bunch of these, and some I haven't listed yet due to sloth, are already implemented and just not published yet because they're not satisfactorily tested, and because I still don't know what I'm doing about portable hooks

https://github.com/StoneCypher/fsl/issues/418

https://github.com/StoneCypher/fsl/issues?q=is%3Aissue+is%3A...

https://github.com/StoneCypher/fsl/issues?q=is%3Aissue+is%3A...

There are, actually, things like what you describe already - SMC, Canopy, and Ragel, by example, and depending on how you look at it, there's sort of an argument for Drakon and some others. I'm making mine because they don't fit my needs, but if you need something right now, they're options.

SMC is probably the best of those in my opinion. It reaches 14 languages including most of the stuff you'll actually want, is durable, near-zero-bug once you learn what it means by its phrasings, reasonably fast, and does mostly everything you're likely to want in practice. It is entirely adequate from basically every angle, something very few state machines can say (mine cannot.)

But also I'm hungry for users, so please try mine and let me know how you think I could improve. I believe that my ease of use characteristics are pretty nice, and my opinion is that ease of use is probably the Genuinely Big Barrier to fsm usage.

My opinion is that mine is simple enough that people who don't know these things can often see the value. To me, that seems important.

  import { sm } from 'jssm';
  
  const coworker = sm`
    not_convinced -> [whats_a_fsm dont_like_fsm js_has_no_lib];
    whats_a_fsm   -> this -> try_it -> ok;
    dont_like_fsm -> why -> [complicated boring intimidating];
     complicated   -> compare_machine_to_code -> oh;
     boring        -> are_case_blocks_a_party -> oh;
     intimidating  -> but_you_can_read_this -> and_you_dont_speak_this -> oh;
    js_has_no_lib -> tons_of_them -> jssm_is_an_easy_one -> oh;
    oh            -> ok -> ill_try_jssm;
  `;
Try giving them this and the resulting graph, and when they look at you funny, afterwards, give them some beefy awful thing with a bunch of control logic from your existing product, rewritten in a state machine, also with the resulting graph

The resulting graph: https://stonecypher.github.io/jssm-viz-demo/graph_explorer.h...

If they're still on the fence, ask them how TCP works and give them a machine to read

TCP machine to read: https://stonecypher.github.io/jssm-viz-demo/graph_explorer.h...

One dollar on PayPal says they'll come around fast

Re: FSL: A programming language to make complex finite state machines easy to create

#67

While most of the site seems broken, at least the online editor is working. There's an example of a traffic light that gives some insight as to the design of the language: https://stonecypher.github.io/jssm-viz-demo/graph_explorer.h... One thing I've learned personally writing live editors is that while recompile on every key seems neat, in practice it is very jarring to have things jump around every keystroke. The p…

> While most of the site seems broken

I didn't expect anyone to find it It's just not done

Workin' on it now ™

.

> This is why I think it's best practice to explicitly recompile on ctrl+enter, even if you have the ability to do it every keystroke.

This is interesting, and I like it

I'm gonna leave it in its current default behavior because I believe that it has a strong impact on ease of onboarding to just see what you did without explicitly requesting it.

But, I think I'm going to make this a configurable option, so that you can have the thing you wanted, and I may even start working this way myself (gonna have to try it and see how it feels.)

Thank you for the idea, and please keep them coming. I appreciate your help.

I am most likely to notice them in the FSL issue tracker: https://github.com/StoneCypher/fsl/issues

Re: FSL: A programming language to make complex finite state machines easy to create

#68
post #64

Earlier quoted context omitted.

JSSM has JSSM-viz. https://github.com/StoneCypher/jssm-viz If you just want one to use, rather than to embed in your own software, The thing everyone's calling a live editor is actually the JSSM-viz demo. You can use that https://stonecypher.github.io/jssm-viz-demo/graph_explorer.h... It's kept outside of the main repo because, like xstate's, it's built on a transcompile of graphviz called viz.js, which is made with…

The problem is that this uses your new custom language which is not yet documented. I had seen this, I asked for alternatives because it doesn't seem to be an option yet . The examples in your README also seem very limited, with no guards/actions/recursion/parallelism (correct me if I'm wrong). The last two I can do without but it seems overly simplistic as of now.

> The examples in your README also seem very limited

Agreed.

.

> with no guards

It's not entirely clear what you mean by a guard. Isn't the entirety of a state machine a guard?

If you mean transitions that are disallowed due to embedded mealy values, that's meant to be handled by the return value from hooks. That runs but isn't published yet because the test cases aren't yet adequate

.

> actions

  const yeah_huh = sm`has_actions 'tell_em' -> neat;`;
or less glibly

  const matter = sm`
  
                   solid  'melt' 
     'freeze'   liquid 'boil' 
     'condense' gas    'ionize' 
     'deionize' plasma;
  
  `;
.

> recursion

State machines don't have control behavior and in general should not have direct expression of "recursion," unless I misunderstand what you mean

If you mean machines self-embedding, that is planned, and I don't know of anyone else who does that

.

> parallelism

Nothing stops you from putting a machine in each of a bunch of threads or web workers or whatever. By example, if you were making a Roller Coaster Tycoon style game, having one FSM to model each park visitor or each ride or each garbage pile or whatever would actually be fairly reasonable.

Granted, I'd probably just make an array of them and process them serially in a single web worker, because you'd want the world synchronized and fast, but, it's doable.

The core concept of a finite state machine has no direct association with process control and within a single finite state machine it's not actually clear to me what parallelism would mean within a single FSM. I've never seen this in any other state machine library. If this is what you mean, I'd like to hear more, possibly including an example API.

It's possible that I misunderstand you.

.

> it seems overly simplistic as of now.

If you can find a finite state machine with more features, please let me know where.

Re: FSL: A programming language to make complex finite state machines easy to create

#69
post #26

I feel like we don’t need a novel language for this. There’s already a pretty-well-known language that’s almost a DSL for “making complex finite-state machines easy to create”: Erlang. I know that sounds wacky, so let me pitch you on that idea :) In ‘primitive’ Erlang (i.e. Erlang without OTP), each FSM state is just a function, that can contain its own event loop (`receive` statement) to accept input, and then can t…

Transpiling to Z3 and Coq is an absolutely fascinating idea.

I will attempt to adopt this. I've no idea where even to start

Re: FSL: A programming language to make complex finite state machines easy to create

#70
post #55

Earlier quoted context omitted.

> I've tried using both of its finite state machine libraries. I'm not talking about gen_fsm or gen_statem — note how I said "without OTP" above. I'm talking about writing Erlang the way it was originally conceived before proc_lib existed — where each process has a module that's exclusively responsible for its own receive loop, rather than being a delegate module for a generic receive-loop manager framework (proc_lib…

> note how I said "without OTP" above I apologize for overlooking this . > You don't call into arbitrary slap-dash non-formalized libraries Respectfully, no, it sounds like you write them yourself, instead . > > FSMs are a great example. You either need to reach outside the Beam VM with `hipe_bifs:array` or you need to copy the entire machine state every time you want to mutate it. > > Why are you mutating something…

> Respectfully, no, it sounds like you write them yourself, instead

I write them myself and prove them, and then use them.

Or, more likely, I take code from elsewhere, reduce it to its core, prove that — if possible; it often isn't, because code from elsewhere is often fundamentally Turing-hard — and then, if I was able to prove it, use it.

Or, even more likely, I use a library of self-contained code that lives inside the prover's model, that someone else already did all the hard work of getting the prover to accept.

Think of it like this: would you call an arbitrary utility function from an HTTP library inside a reference implementation of a cryptographic cipher?

No, because that arbitrary utility function has no abstract-mathematical equivalent. You can't prove anything about code that contains a black-box like that. The code, with the call to the HTTP library inside it, isn't a discrete-mathematics-specified-in-procedural-language proof of anything any more.

If you want to prove anything about code, the code needs to 1. live inside your proof (along with all its transitive dependencies), and 2. be modified such that all its base types are types that have complete models in your chosen prover's algebra (e.g. no non-fixed-size bit-vectors.)

> I apologize, but you and I have strongly contrasting opinions here.

What are FSMs "for" in your mind, then?

I use them when I want to be able to prove the behavior of something formally, and then reuse the proof as a production-quality implementation of that thing as-is. This allows the design↔implementation equivalent of "documentation drift" to be avoided — you don't have to trust that the programmer that translated the math into code did it correctly this time; you just have to trust a single compiler/code generator (that itself can have been proof-verified.)

I use FSMs for the same reason I use PEGs, or cellular automata, or other such formalisms, in place of just trying to prove an abstract Turing machine: because there are known ways to prove certain properties of these low-power formalisms in bounded time, while there's no known (or sometimes, no possible) equivalent for Turing machines generally.

> My library, and finite state machines, which are the superfamily containing DFA and a great many other things. DFA is not a common interpretation of the phrase FSM; usually that phrase means a Mealy machine or a Moore machine, or maybe a Harel machine.

You're being a lot more pedantic here than I was attempting to be. I meant to refer to "deterministic finite-state transducers" — the class of thing to which Mealy machines are a subset. But people on HN don't know what those are, while they do generally know what a DFA is. And a DFA has the same computational power as a Mealy machine generally; it's just a special construction of one (like a Binary Search Tree is just a special construction of a Binary Tree.)

I was trying to contrast with NFAs, which aren't FSMs (deterministic finite-state transducers) at all, but rather are computationally-equivalent to pushdown automata.

Maybe, rather than a DFA, I should have made the analogy to LR parsing, which also has equivalent abstract-computational-power requirements.

Post reply on HN