ztellman / automat

better automata through combinators
588 stars 50 forks source link

`valid-transitions` fn? #24

Open timvisher opened 9 years ago

timvisher commented 9 years ago

Related to #23, the other question I'm interested in asking the fsm is, given the current state, what inputs would be valid. This would allow me to return to the user in the 409 the statement: you asked me to do this, which is wrong, but you could've asked me to do these, which would have been ok.

Again, given the tools available in fsm I'm unclear how to accomplish that goal. Any help there?

martinklepsch commented 8 years ago

Hey @timvisher, just stumbled upon this while looking for a solution myself. I came up with the following:

(defn possible-transitions [compiled-fsm state]
  (let [alphabet (f/alphabet (:fsm (meta compiled-fsm)))]
    (set (filter (fn [t] (a/advance compiled-fsm state t nil)) alphabet))))

This obviously isn't ideal computation-wise but I haven't been able to find the right knobs inside the library to give me the same result. For my use case it's ok.

@ztellman If there's a way to achieve this without brute-force as above an addition to the Readme would be a great :)

martinklepsch commented 8 years ago

I just noticed that the above snippet does trigger actions which makes it potentially un-pure making it more or less useless. Anybody came up with a better approach in the meantime that is side-effect free?

martinklepsch commented 8 years ago

My new approach looks like this:

(defn dry-run-wrap
  "Wrap `action-fn` so that it only calls `action-fn` if the FSM's state
   does not contain a truthy value under `::dry-run`."
  [action-fn]
  (fn [state input]
    (if (::dry-run state)
      state
      (action-fn state input))))

(defn possible-transitions [compiled-fsm state]
  (let [alphabet (f/alphabet (:fsm (meta compiled-fsm)))
        dry-run  (assoc state ::dry-run true)]
    ;; SIGNAL using [t] here means we assume the FSMs signal function is `first`
    (set (filter (fn [t] (a/advance compiled-fsm dry-run [t] false)) alphabet))))

I'm using dry-run-wrap to wrap action functions so that they are effectively no-ops if the ::dry-run key contains a truthy value.

osfameron commented 7 years ago

Agree that a way to check what the output states are would be a useful addition to the library, for various introspection abilities and tweaks. (Presumably the viz view function uses some kind of similar hook, but I don't understand the code base well enough to see quite how.)