我不同意有人认为有限状态机(FSM)容易实现。这种看法非常短视,表明其要么不了解替代方案,要么缺乏处理复杂状态机的经验。
根本问题在于状态机图形很显然,但FSM代码并不是那么简单易懂的。一旦你超过十几个状态和大量的转换,FSM代码就变得丑陋难懂。
有一些工具可以让你绘制状态机,并生成Java代码。但我不知道是否有任何开源工具可以做到这一点。
现在回到Erlang/Scala上,Scala也有Actor和消息传递功能,而且基于JVM,因此在你的约束条件下,它可能比Erlang更好。
Scala也有DFA/NFA库,虽然它不是特别好用。它支持将任意正则表达式(即字面量不必是字符)转换为DFA/NFA。
下面会贴出使用它的一些代码。在这段代码中,我们创建了一个FSM,它将接受任何单词列表的任意前缀的顺序组合,目的是查找没有预定义键位的菜单选项。
import scala.util.regexp._
import scala.util.automata._
object MyLang extends WordExp {
type _regexpT = RegExp
type _labelT = MyChar
case class MyChar(c:Char) extends Label
}
import MyLang._
object MyBerrySethi extends WordBerrySethi {
override val lang = MyLang
}
def matchDet(pat: DetWordAutom[MyChar], seq: Seq[Char]): Boolean =
!pat.isSink((0 /: seq) ((state, c) => pat.next(state, MyChar(c))))
def compile(pat: MyLang._regexpT) =
new SubsetConstruction(MyBerrySethi.automatonFrom(pat, 100000)).determinize
def Quest(rs: _regexpT*) = Alt(Eps, Sequ(rs: _*))
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)) : _*)
def regexList(l : List[String]) = l.map(s => compile(phraseRegex(s)) -> s)
def regexSearcher(l : List[String]) = {
val r = regexList(l)
(s : String) => r.filter(t => matchDet(t._1, s)).map(_._2)
}