progs/automata.scala
changeset 93 4794759139ea
parent 92 e85600529ca5
equal deleted inserted replaced
92:e85600529ca5 93:4794759139ea
       
     1 
       
     2 // a class for deterministic finite automata,
       
     3 // the type of states is kept polymorphic
       
     4 
       
     5 case class Automaton[A](start: A, states: Set[A], delta: Map[(A, Char), A], fins: Set[A]) {
       
     6 
       
     7   // the transition function lifted to list of characters
       
     8   def deltas(q: A, cs: List[Char]) : Either[A, String] = 
       
     9     if (states.contains(q)) cs match {
       
    10       case Nil => Left(q)
       
    11       case c::cs => 
       
    12         if (delta.isDefinedAt(q, c)) deltas(delta(q, c), cs)
       
    13         else Right(q + " does not have a transition for " + c)
       
    14     }
       
    15     else Right(q + " is not a state of the automaton")
       
    16 
       
    17   // wether a string is accepted by the automaton
       
    18   def accepts(s: String) = deltas(start, s.toList) match {
       
    19     case Left(q) => fins.contains(q)
       
    20     case _ => false
       
    21   } 
       
    22 }
       
    23 
       
    24 
       
    25 // translating a regular expression into a finite
       
    26 // automaton
       
    27 
       
    28 abstract class Rexp
       
    29 
       
    30 case object NULL extends Rexp
       
    31 case object EMPTY extends Rexp
       
    32 case class CHAR(c: Char) extends Rexp 
       
    33 case class ALT(r1: Rexp, r2: Rexp) extends Rexp
       
    34 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
       
    35 case class STAR(r: Rexp) extends Rexp
       
    36 
       
    37 implicit def string2rexp(s : String) = { 
       
    38   def chars2rexp (cs: List[Char]) : Rexp = cs match {
       
    39     case Nil => EMPTY
       
    40     case c::Nil => CHAR(c)
       
    41     case c::cs => SEQ(CHAR(c), chars2rexp(cs))
       
    42   }
       
    43   chars2rexp(s.toList)
       
    44 }
       
    45 
       
    46 def nullable (r: Rexp) : Boolean = r match {
       
    47   case NULL => false
       
    48   case EMPTY => true
       
    49   case CHAR(_) => false
       
    50   case ALT(r1, r2) => nullable(r1) || nullable(r2)
       
    51   case SEQ(r1, r2) => nullable(r1) && nullable(r2)
       
    52   case STAR(_) => true
       
    53 }
       
    54 
       
    55 def der (r: Rexp, c: Char) : Rexp = r match {
       
    56   case NULL => NULL
       
    57   case EMPTY => NULL
       
    58   case CHAR(d) => if (c == d) EMPTY else NULL
       
    59   case ALT(r1, r2) => ALT(der(r1, c), der(r2, c))
       
    60   case SEQ(r1, r2) => if (nullable(r1)) ALT(SEQ(der(r1, c), r2), der(r2, c))
       
    61                       else SEQ(der(r1, c), r2)
       
    62   case STAR(r) => SEQ(der(r, c), STAR(r))
       
    63 }
       
    64 
       
    65 
       
    66 // Here we construct an automaton whose
       
    67 // states are regular expressions
       
    68 type State = Rexp
       
    69 type States = Set[State]
       
    70 type Transition =  Map[(State, Char), State]
       
    71 
       
    72 // we use as an alphabet all lowercase letters
       
    73 val alphabet = "abcdefghijklmnopqrstuvwxyz".toSet
       
    74 
       
    75 def goto(q: State, c: Char, qs: States, delta: Transition) : (States, Transition) = {
       
    76   val q_der : State = der(q, c)
       
    77   if (qs.contains(q_der)) (qs, delta + ((q, c) -> q))
       
    78   else explore(qs + q_der, delta + ((q, c) -> q_der), q_der)
       
    79 }
       
    80 
       
    81 def explore (qs: States, delta: Transition, q: State) : (States, Transition) =
       
    82   alphabet.foldRight[(States, Transition)] (qs, delta) ((c, qsd) => goto(q, c, qsd._1, qsd._2)) 
       
    83 
       
    84 
       
    85 def mk_automaton (r: Rexp) : Automaton[Rexp] = {
       
    86   val (qs, delta) = explore(Set(r), Map(), r);
       
    87   val fins = for (q <- qs if nullable(q)) yield q;
       
    88   Automaton[Rexp](r, qs, delta, fins)
       
    89 }
       
    90 
       
    91 val A = mk_automaton(ALT("ab","ac"))
       
    92 
       
    93 A.start
       
    94 A.states.toList.length
       
    95 
       
    96 println(A.accepts("bd"))
       
    97 println(A.accepts("ab"))
       
    98 println(A.accepts("ac"))
       
    99 
       
   100 val r1 = STAR(ALT("a","b"))
       
   101 val r2 = SEQ("b","b")
       
   102 val r3 = SEQ(SEQ(SEQ(r1, r2), r1), "a")
       
   103 val B = mk_automaton(r3)
       
   104 
       
   105 B.start
       
   106 B.states.toList.length