automata

FIXME: write description


License
EPL-1.0

Documentation

Automata

A simple automata library, shamelessly cribbed from Zach Tellman's ztellman/automat. A good breakdown of automata theory is on Wikipedia. Particularly, I'm interested in finite state machines.

A simple finite state machine

This automaton consists of states (represented in the figure by circles) and transitions (represented by arrows). As the automaton sees a symbol of input, it makes a transition (or jump) to another state, according to its transition function, which takes the current state and the recent symbol as its inputs.

[automata "0.1.0"]

NOTE

Only scalar and star types are implemented. This is still pre-alpha software.

Usage

You can create automaton like so.

(require '[automata.core :refer [automaton]]')

(automaton [:a :b :c :d])
(automaton [:a (a/+ :b) :c :d])
(automaton [:a (a/* :b) :c :d])
(automaton [:a (a/? :b) :c :d])
(automaton [:a (a/bound 2 4 :b) :c :d])
(automaton [:a (a/and :b :c) :d])
(automaton [:a (a/or :b :c) :d])
(automaton [:a (a/not :b) :c :d])
(automaton [1 (a/range 2 10)11])

Advancing through the states is done like so. Starting With regular scalars.

=> (def a (automaton [:a :b :c :d]))

=> (advance a :a)
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :b} {:matcher :c} {:matcher :d})
    :state {:matcher :a}
    :history (nil {:state {:matcher :a} :input :a :transition :automata.core/match})}

=> (-> a (advance :a) (advance :b))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :c} {:matcher :d})
    :state {:matcher :b}
    :history (nil
                {:state {:matcher :a} :input :a :transition :automata.core/match}
                {:state {:matcher :b} :input :b :transition :automata.core/match})}

=> (advance a :b)
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :state nil
    :history [nil]
    :error {:type :invalid-trasition :input :b :matcher {:matcher :a}}}


=> (-> a (advance :a) (advance :a))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :b} {:matcher :c} {:matcher :d})
    :state {:matcher :a}
    :history (nil {:state {:matcher :a} :input :a :transition :automata.core/match})
    :error {:type :invalid-trasition :input :a :matcher {:matcher :b}}}

Here, scalars mixed with stars.

=> (def b (automaton [(* :a) :b :c :d]))

=> (-> b (advance :a) (advance :a))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :b} {:matcher :c} {:matcher :d})
    :state {:matcher :a}
    :history
    (nil
     {:state {:matcher :a} :input :a :transition :automata.core/match}
     {:state {:matcher :a} :input :a :transition :automata.core/match})}


=> (-> b (advance :a) (advance :b))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :c} {:matcher :d})
    :state {:matcher :b}
    :history
    (nil
     {:state {:matcher :a} :input :a :transition :automata.core/match}
     {:state {:matcher :b} :input :b :transition :automata.core/match})}

Star in the midde.

=> (def c (automaton [:a (* :b) :c :d]))

=> (-> c (advance :a) (advance :c))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :d})
    :state {:matcher :c}
    :history
    (nil
     {:state {:matcher :a} :input :a :transition :automata.core/match}
     {:state {:matcher :b} :input :c :transition :automata.core/noop}
     {:state {:matcher :c} :input :c :transition :automata.core/match})}

Multiple stars.

=> (def d (automaton [(* :a) (* :b) :c :d]))

=> (-> d (advance :b) (advance :b) (advance :c))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :d})
    :state {:matcher :c}
    :history
    (nil
     {:state {:matcher :a} :input :b :transition :automata.core/noop}
     {:state {:matcher :b} :input :b :transition :automata.core/match}
     {:state {:matcher :b} :input :b :transition :automata.core/match}
     {:state {:matcher :c} :input :c :transition :automata.core/match})}
  

=> (-> d (advance :c))
=> {:states ({:matcher :a} {:matcher :b} {:matcher :c} {:matcher :d})
    :run ({:matcher :d})
    :state {:matcher :c}
    :history
    (nil
     {:state {:matcher :a} :input :c :transition :automata.core/noop}
     {:state {:matcher :b} :input :c :transition :automata.core/noop}
     {:state {:matcher :c} :input :c :transition :automata.core/match})}

TODO

  • remaining combinators
  • cycle between a > b > a
  • OR condition a > b > c | a > c
  • AND condition a > b > c | a > d > c
  • NOT condition a > !b > c
  • range
  • bound
  • nested automata

License

Copyright © 2018 FIXME

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.