No estoy de acuerdo en que los FSM sean triviales. Esto es muy corto de miras y muestra una la falta de familiaridad con las alternativas, o la falta de experiencia con máquinas de estado complejas.
el problema fundamental es que una máquina de estados gráfico es obvio, pero FSM código no lo es. una vez que llegue más allá de una docena de estados y una veintena de transiciones, el código FSM se vuelve feo y difícil de seguir.
Ther Son herramientas mediante las cuales dibujan la máquina de estados y generan código Java para ellas. Sin embargo, no conozco ninguna herramienta de código abierto para eso.
Ahora, volviendo a Erlang/Scala, Scala también tiene actores y mensaje que pasa, y se basa en la JVM, por lo que podría ser una mejor alternativa que Erlang debido a sus limitaciones.
También hay una biblioteca de DFA/NFA en Scala, aunque no es particularmente buena. Admite la conversión de expresiones regulares arbitrarias (es decir, los literales no necesitan ser caracteres) en DFA/NFA.
Voy a publicar un código a continuación usándolo.En este código, la idea es crear un FSM que acepte cualquier combinación secuencial de prefijos arbitrarios para una lista de palabras, la idea es buscar opciones de menú sin keybinds predefinidos.
import scala.util.regexp._
import scala.util.automata._
// The goal of this object below is to create a class, MyChar, which will
// be the domain of the tokens used for transitions in the DFA. They could
// be integers, enumerations or even a set of case classes and objects. For
// this particular code, it's just Char.
object MyLang extends WordExp {
type _regexpT = RegExp
type _labelT = MyChar
case class MyChar(c:Char) extends Label
}
// We now need to import the types we defined, as well as any classes we
// created extending Label.
import MyLang._
// We also need an instance (singleton, in this case) of WordBerrySethi,
// which will convert the regular expression into an automatum. Notice the
// language being used is MyLang.
object MyBerrySethi extends WordBerrySethi {
override val lang = MyLang
}
// Last, a function which takes an input in the language we defined,
// and traverses the DFA, returning whether we are at a sink state or
// not. For other uses it will probably make more sense to test against
// both sink states and final states.
def matchDet(pat: DetWordAutom[MyChar], seq: Seq[Char]): Boolean =
!pat.isSink((0 /: seq) ((state, c) => pat.next(state, MyChar(c))))
// This converts a regular expression to a DFA, with using an intermediary NFA
def compile(pat: MyLang._regexpT) =
new SubsetConstruction(MyBerrySethi.automatonFrom(pat, 100000)).determinize
// Defines a "?" function, since it isn't provided by the library
def Quest(rs: _regexpT*) = Alt(Eps, Sequ(rs: _*)) // Quest(pat) = Eps|pat = (pat)?
// And now, the algorithm proper. It splits the string into words
// converts each character into Letter[MyChar[Char]],
// produce the regular expression desired for each word using Quest and Sequ,
// then the final regular expression by using Sequ with each subexpression.
def words(s : String) = s.split("\\W+")
def wordToRegex(w : String) : Seq[MyLang._regexpT] = w.map(c => Letter(MyChar(c)))
def wordRegex(w : String) = Quest(wordToRegex(w) reduceRight ((a,b) => Sequ(a, Quest(b))))
def phraseRegex(s : String) = Sequ(words(s).map(w => wordRegex(w)) : _*)
// This takes a list of strings, produce a DFA for each, and returns a list of
// of tuples formed by DFA and string.
def regexList(l : List[String]) = l.map(s => compile(phraseRegex(s)) -> s)
// The main function takes a list of strings, and returns a function that will
// traverse each DFA, and return all strings associated with DFAs that did not
// end up in a sink state.
def regexSearcher(l : List[String]) = {
val r = regexList(l)
(s : String) => r.filter(t => matchDet(t._1, s)).map(_._2)
}
Lo _are_ sus requisitos? ¿Y tus limitaciones? –
Estoy atascado ahora con una imagen mental del Monstruo Volador de Espagueti. El paso de mensajes se puede implementar a través de apéndices noodly. –