Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Sep 03 00:51

    dependabot[bot] on npm_and_yarn

    (compare)

  • Sep 03 00:51
    dependabot[bot] closed #36
  • Sep 03 00:51
    dependabot[bot] commented #36
  • Sep 03 00:51
    dependabot[bot] labeled #60
  • Sep 03 00:51
    dependabot[bot] opened #60
  • Sep 03 00:51

    dependabot[bot] on npm_and_yarn

    Bump immer from 2.1.5 to 9.0.6 … (compare)

  • Aug 12 04:31
    dependabot[bot] labeled #59
  • Aug 12 04:31
    dependabot[bot] opened #59
  • Aug 12 04:31

    dependabot[bot] on npm_and_yarn

    Bump path-parse from 1.0.6 to 1… (compare)

  • Aug 11 00:49
    dependabot[bot] labeled #58
  • Aug 11 00:49
    dependabot[bot] opened #58
  • Aug 11 00:49

    dependabot[bot] on npm_and_yarn

    Bump path-parse from 1.0.6 to 1… (compare)

  • Aug 10 22:48
    dependabot[bot] labeled #57
  • Aug 10 22:48
    dependabot[bot] opened #57
  • Aug 10 22:48

    dependabot[bot] on npm_and_yarn

    Bump path-parse in /angular4-Bo… (compare)

  • Aug 04 20:53
    dependabot[bot] labeled #56
  • Aug 04 20:53
    dependabot[bot] opened #56
  • Aug 04 20:53

    dependabot[bot] on npm_and_yarn

    Bump tar from 2.2.1 to 2.2.2 in… (compare)

  • Aug 03 19:29
    dependabot[bot] labeled #55
  • Aug 03 19:29
    dependabot[bot] opened #55
Jean-Jacques Dubray
@jdubray
absolutely, I just follow the semantics of TLA+ and what Dr. Lamport calls an action
Edward Mulraney
@edmulraney
perfect, thanks for clarifying
Edward Mulraney
@edmulraney
Thinking more on SAM semantics. I'm looking into whether you can achieve SAM semantics just using an FSM as we've described, as long as the transition supports a guard of some sort. I.e. the state transition may be valid, but unless the application state (model) is ready to support that transition, we should reject the transition
I think that's what you were getting at with your Three approximations you shouldn't make article? That the glass might be empty so altho drink is a valid action, it should be rejected if the glass is empty
The event should still fire (like in real life), but the state machine should reject the transition attempt if not valid within the current app state
i.e. if i pick up an empty glass an try and drink from it, I am still picking it up and attempting to drink. but no water will leave the glass :)
Jean-Jacques Dubray
@jdubray
that's kind of where things break down a bit, the problem has been that pure FSM semantics are not very useful for things other than light switches. So you can start tweaking these semantics or you can jump to TLA+ which is really where you want to be. During the short discussions I had with Dr. Lamport, we focused on the PC variable and I believe since then he has been more specific and started talking about control state which he didn't seem to do before, at least in the videos that I had watched at the time. So I would say that (as you mentioned, these are macro-states) they avoid quite a bit of boiler plate, so I really like that addition, but I would discourage trying to bridge further, what you want is really to use a next-state relation, there is just no scalable way (again in scope, not talking about runtime here) to tweak the programming model of FSM. At least that's what I believe, otherwise someone would have found it in the last 50 years or so that people have tried. There are real benefits in thinking in terms of macro-states, but that's it after that, you are back to the code level.
the "pick up the glass" has transitions/macro states of its own (picked-up/on the table)
Jean-Jacques Dubray
@jdubray
Programming models are very stubborn animals... After spending 20 years in Model-Driven Software Engineering, mostly focusing on Business Process Management and trying to build a programming model where business processes are first-class citizens, I realized that you cannot do it in a declarative only way. Code fulfills an essential function, that's why I say the pillars of programming are STAR: State, Type, Action and Relationships.
I wrote this article in 2009 to kind of express my findings in that endeavor https://www.infoq.com/articles/mop/
Jean-Jacques Dubray
@jdubray
What TLA+ taught me is that there is a distinction between Types (OOP) and State or Actions (FP) and State. We have not focused enough on State when writing code. State is not a concern of structs and functions. Not to mention relationships. That seems to be root of a large class of problems when writing real-world code.
Jean-Jacques Dubray
@jdubray
Please understand that we have never been taught to deal with State properly, it has been an either or king of thing with FSM (mostly a curiosity). TLA+ is not taught in Computer Science undergraduate courses and even when it is taught, it is not taught as a programming model. Temporal Programming is not a thing, yet.
Jean-Jacques Dubray
@jdubray
@jeffbski who was participating in this community early on provides for SAM in redux-logic https://www.npmjs.com/package/redux-logic
Jean-Jacques Dubray
@jdubray
@edmulraney I found an easy way to add guards to the state machine definition. In SAM the logical way to use guards is as a reactor that block the next-step action when the guard evaluates to false in the current step. Since the step is controlled, we do not need to front-end the model acceptors with the guards. This will rely on the existing implemented of "allowedActions" in the sam-pattern lib. I'll work on it over the week-end.
Edward Mulraney
@edmulraney
Sounds interesting. Looking forward to seeing it
Jean-Jacques Dubray
@jdubray
Guards have been added as follows:
const clock = fsm({
        pc: 'status',
        pc0: 'TOCKED',
        actions: {
          TICK_GUARDED: ['TICKED'],
          TOCK_GUARDED: ['TOCKED']
        },
        states: {
          TICKED: {
            transitions: ['TOCK_GUARDED'],
            guards: [{
              action: 'TOCK_GUARDED',
              // once the counter reaches 5, TICK_GUARDED and TOCK_GUARDED
              // are no longer allowed
              condition: ({ counter }) => counter < 5
            }]
          },
          TOCKED: {
            transitions: ['TICK_GUARDED'],
            guards: [{
              // The action name can be ommitted, in which case the first element of the transition
              // array will be used
              // action: 'TICK_GUARDED',
              condition: ({ counter }) => counter < 5
            }]
          }
        },
        deterministic: true,
        lax:false,
        enforceAllowedTransitions: true,
        blockUnexpectedActions: true
      })
Edward Mulraney
@edmulraney
Nice. This has got me wondering. If the FSM supported NAP as well as guard, wouldn’t it be SAM compliant at that point?
Radu
@raduab_gitlab
quick question, for the sam-pattern library: if actions & acceptors are an array, how does it know which one you want to use? or does it always start with the first and just cycle through?
Radu
@raduab_gitlab
also how one can compose allowedActions as I didn't find any example in the sam-pattern library git repo. thanks
Jean-Jacques Dubray
@jdubray
@radu, so the one to use are guarded by proposal elements, they all looks like if (proposal.xyz) { model.xyz = f(xyz) }. Of course it can depend on several elements of the proposal but rarely on the action itself. The idea is to break the coupling action - state that you find in FSM.
Otherwise, yes, they are executed in the order in which the array is constructed, but they should be design to be independent of the order (not always possible). They are separate from reactors which should react to the proposal mutations, again, in general in an order independent way.
@edmulraney it does support NAPs! but you'll never get full compliance since the structure of FSM is only a subset of what SAM can do.
Radu
@raduab_gitlab
@jdubray that makes sense! what about my second question, how should I implement allowedActions in the sam-pattern. do you have an example somewhere?
Jean-Jacques Dubray
@jdubray
@radu all samples are in the test. I don't release a feature without testing it, thought there might be corner cases I miss:
 it('should accept a limited set of actions', () => {
      const SAMAllowedActionTest = createInstance({ instanceName: 'allowed' })

      expect(SAMAllowedActionTest).to.not.equal(SAM)

      const { intents } = SAMAllowedActionTest({

        initialState: {
          counter: 0
        },

        component: {
          actions: [
            () => ({ incBy1: 1 }),
            () => ({ incBy2: 1 })
          ],
          acceptors: [
            model => ({ incBy1, incBy2 }) => {
              if (E(incBy1) || E(incBy2)) {
                model.counter += (incBy1 || 0) + (incBy2 || 0)
              }
            }
          ]
        },

        render: state => expect(state.counter).to.be.lessThan(4)
      })
      const [incBy1, incBy2] = intents
      SAMAllowedActionTest({ allow: { actions: [incBy2] } })
      incBy1()
      incBy2()
      incBy1()

      setRender(state => expect(state.counter).to.be.equal(1))
    })
this is how you change it: SAMAllowedActionTest({ allow: { actions: [incBy2] } })
Radu
@raduab_gitlab

I guess this would be better placed into a reactor function? e.g.

reactors: [
  model => ({ action }) => {
    ...
    allow({ actions: [anotherAction] })
  },
  model => ({ anotherAction }) => {
    ...
    allow({ actions: [action] })
  }
]

What would be the allow() function in the above example?

Jean-Jacques Dubray
@jdubray
The idea is that allowed intents would change at every step, so you need to mount that logic after the SAM instance has returned the intents. Now with the sam-fsm library, it also works with action labels, so you can use the sam-fsm very effectively to controlled the allowed intents.
Otherwise, yes, the reactors would be a great place to specify them.
Jean-Jacques Dubray
@jdubray
I'll add these labels to the sam-pattern library, that seems to be a reasonable addition, rather than requiring the intent instance's reference.
Jean-Jacques Dubray
@jdubray
I have updated the action definition to integrate a label. You can now use:
actions: [
          ['TICK', tick],
          ['TOCK', tock],  // a SAM action associated to the label TOCK
         tack  // a regular (not labeled) action
        ],
That means that now you can also label actions in SAM (without fsm) and therefore you can defined the allowed actions as an array of labels (string)
Jean-Jacques Dubray
@jdubray

Graphviz offers a nice state machine editor, for instance (http://magjac.com/graphviz-visual-editor/):

digraph rocket_launcher {
    rankdir=LR;
    size="8,5"
    node [shape = doublecircle]; ready;
    node [shape = circle];
    ready -> started [label = "START"];
    started -> ticking [label = "TICK"];
    ticking -> ticking [label = "TICK"];
    ticking -> aborted [label = "ABORT"];
    ticking -> launching [label = "LAUNCH"];
    aborted -> ready [label = "RESET"];
    launching -> ready [label = "RESET"];
}

You can even save them in the browser local storage

I am adding a graphviz output to sam-fsm
Jean-Jacques Dubray
@jdubray
these shapes look nicer:
ready [shape = doublecircle fontcolor=white style=filled color=black]
node [shape = Mrecord];
Edward Mulraney
@edmulraney
Nice find, thanks for sharing
Jean-Jacques Dubray
@jdubray
Ok, I added to the sam-fsm library! v0.9.16
@edmulraney let me know if you see anything else, otherwise, I'll call it a 1.0.0
I found a slightly prettier design:
digraph fsm_diagram {
rankdir=LR;
size="8,5"
READY [shape = circle margin=0 fixedsize=true width=0.33 fontcolor=black style=filled color=black label="\n\n\nREADY"]
END [shape = doublecircle margin=0 style=filled fontcolor=white color=black]
node [shape = Mrecord];
READY -> TICKED [label = "START"]
TICKED -> TOCKED [label = "TOCK"];
TOCKED -> TICKED [label = "TICK"];
TOCKED -> END [label = "STOP"];

}
image.png
Edward Mulraney
@edmulraney
Last thing I'd suggest, and you may have done this already, is sensible defaults
looked like quite a large object to initialise the FSM with. Would be nice if you could just pass the transitions, and it defaults to just a standard FSM (deterministic)
Jean-Jacques Dubray
@metapgmr_twitter
Yes, it's already done, the first state is also used as the start state, so you can just pass a transition object.
Jean-Jacques Dubray
@jdubray
image.png
I was actually able to add conditions as well (last transition):
Edward Mulraney
@edmulraney
So does sam-fsm autogenerate that diagram, with conditions? I imagine you have to add that manually
Jean-Jacques Dubray
@metapgmr_twitter
Yes! The textual form. What I had in mind is that during the test phase in your build pipeline you could autogenerate the png file from a local graphviz instance and check it back in with a link in the readme file. It would be autidocumenting at its best.
Jean-Jacques Dubray
@jdubray
There is also dotuml, I'll add an output tonight, there is a nice plugin for vscode: https://dotuml.com/documentation.html#secDiagramState
Jean-Jacques Dubray
@jdubray
I am working on adding composite states: https://www.uml-diagrams.org/state-machine-diagrams.html#composite-state
That sounds like a reasonable feature

Here is the specification:
Since a SAM instance can run multiple state machine, the sam-fsm library also supports the concept of composite state when a state machine can only accept actions when another state machine is in a particular state. The composite state fsm can also be programmed to execute automatic actions on the parent fsm on specific states (success, failure,...)

The composite descriptor specifies the composite state label of the parent fsm (COMPOSITE_STATE in the snippet below). That state value acts as a global guard of the composite fsm. The composite fsm will start in the pc0 state each time the parent transitions to the composite state.

Conversely, the composite fsm can specify automatic actions on the parent fsm as composite transitions. On a given state (for instance END, the composite fsm will automatically execute the specified parent action and pass the proposal parameters (in addition to its own state)).

When the parent and or composite fsm use their local states, the same logic applies.

const parentFSM = fsm({ 
  pc: 'parentStatus', 
  states: {
    COMPOSITE_STATE: { ... }
  },
  ... 
})

const compositeStateFSM = fsm({ 
        ...
        composite: {
          onState: { pc: 'parentStatus', label: 'COMPOSITE_STATE' },
          transitions: [
            { onState: 'END', action: 'PARENT_ACTION', proposal: ['counter'] }
          ]
        }
        ...
})