// DFAs and NFAs based on Scala's partial functions// edges of the DFAs and NFAstype Edge[A, C] = PartialFunction[(A, C), A]// some states for test cases abstract class Statecase object Q0 extends Statecase object Q1 extends Statecase object Q2 extends Statecase object Q3 extends Statecase object Q4 extends Statecase object Q5 extends Statecase object Q6 extends State// class for DFAscase class DFA[A, C](start: A, // starting state trans: Edge[A, C], // transition fins: A => Boolean) { // final states // given a state and a character, // what is the next state, if there is any? def next(q: A, c: C) : Option[A] = trans.lift.apply((q, c)) // given a state and a string, what is the next state? def nexts(q: A, s: List[C]) : Option[A] = s match { case Nil => Some(q) case c::cs => next(q, c).flatMap(nexts(_, cs)) } // is a string accepted by an DFA? def accepts(s: List[C]) : Boolean = nexts(start, s) match { case None => false case Some(q) => fins(q) }}// DFA 1val dtrans1 : Edge[State, Char] = { case (Q0, 'a') => Q0 case (Q0, 'b') => Q1 }val dfa1 = DFA(Q0, dtrans1, Set[State](Q1))dfa1.accepts("aaab".toList) // truedfa1.accepts("aacb".toList) // false// another DFA testabstract class Scase object S0 extends Scase object S1 extends Scase object S2 extends Scase object Sink extends S// transition function// S0 --a--> S1 --a--> S2val sigma : Edge[S, Char] = { case (S0, 'a') => S1 case (S1, 'a') => S2 case _ => Sink }val dfa1a = DFA(S0, sigma, Set[S](S2))dfa1a.accepts("aa".toList) //truedfa1a.accepts("".toList) //falsedfa1a.accepts("ab".toList) //false// class for NFAscase class NFA[A, C](starts: Set[A], // starting states trans: Set[Edge[A, C]], // transition edges fins: A => Boolean) { // final states // given a state and a character, what is the set of next states? def next(q: A, c: C) : Set[A] = trans.flatMap(_.lift.apply((q, c))) // given some states and a character, what is the set of next states? def nexts(qs: Set[A], c: C) : Set[A] = qs.flatMap(next(_, c)) // given some states and a string, what is the set of next states? def nextss(qs: Set[A], s: List[C]) : Set[A] = s match { case Nil => qs case c::cs => nextss(nexts(qs, c), cs) } // is a string accepted by an NFA? def accepts(s: List[C]) : Boolean = nextss(starts, s.toList).exists(fins)}// NFA test cases// 1 val trans1 = Set[Edge[State, Char]]( { case (Q0, 'a') => Q1 }, { case (Q0, _) => Q0 }, { case (Q1, _) => Q2 }, { case (Q2, _) => Q3 }, { case (Q3, _) => Q4 }, { case (Q4, 'b') => Q5 }, { case (Q5, 'c') => Q6 })val nfa1 = NFA(Set[State](Q0), trans1, Set[State](Q6))nfa1.accepts("axaybzbc".toList) // truenfa1.accepts("aaaaxaybzbc".toList) // truenfa1.accepts("axaybzbd".toList) // false// 2val trans2 = Set[Edge[State, Char]]( { case (Q0, 'a') => Q0 }, { case (Q0, 'a') => Q1 }, { case (Q0, 'b') => Q2 }, { case (Q1, 'a') => Q1 }, { case (Q2, 'b') => Q2 })val nfa2 = NFA(Set[State](Q0), trans2, Set[State](Q2))nfa2.accepts("aa".toList) // falsenfa2.accepts("aaaaa".toList) // falsenfa2.accepts("aaaaab".toList) // truenfa2.accepts("aaaaabbb".toList) // truenfa2.accepts("aaaaabbbaaa".toList) // falsenfa2.accepts("ac".toList) // false// 3val trans3 = Set[Edge[State, Char]]( { case (Q0, _) => Q0 }, { case (Q0, 'a') => Q1 }, { case (Q0, 'b') => Q3 }, { case (Q1, 'b') => Q2 }, { case (Q2, 'c') => Q5 }, { case (Q3, 'c') => Q4 }, { case (Q4, 'd') => Q5 })val nfa3 = NFA(Set[State](Q0), trans3, Set[State](Q5))nfa3.accepts("aaaaabc".toList) // truenfa3.accepts("aaaabcd".toList) // truenfa3.accepts("aaaaab".toList) // falsenfa3.accepts("aaaabc".toList) // truenfa3.accepts("aaaaabbbaaa".toList) // false// subset, or powerset, constructiondef powerset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = { DFA(nfa.starts, { case (qs, c) => nfa.nexts(qs, c) }, _.exists(nfa.fins))}val dfa2 = powerset(nfa1)dfa2.accepts("axaybzbc".toList) // truedfa2.accepts("aaaaxaybzbc".toList) // truedfa2.accepts("axaybzbd".toList) // falseval dfa3 = powerset(nfa2)dfa3.accepts("aa".toList) // falsedfa3.accepts("aaaaa".toList) // falsedfa3.accepts("aaaaab".toList) // truedfa3.accepts("aaaaabbb".toList) // truedfa3.accepts("aaaaabbbaaa".toList) // falsedfa3.accepts("ac".toList) // falseimport scala.annotation.tailrec@tailrecdef fixpT[A](f: A => A, x: A): A = { val fx = f(x) if (fx == x) x else fixpT(f, fx) }case class eNFA[A, C](starts: Set[A], // starting state trans: Set[Edge[A, Option[C]]], // transition edges fins: A => Boolean) { // final states def enext(q: A) : Set[A] = trans.flatMap(_.lift.apply((q, None))) def enexts(qs: Set[A]) : Set[A] = qs ++ qs.flatMap(enext(_)) // epsilon closure def ecl(qs: Set[A]) : Set[A] = fixpT(enexts, qs) def next(q: A, c: C) : Set[A] = trans.flatMap(_.lift.apply((q, Some(c)))) def nexts(qs: Set[A], c: C) : Set[A] = qs.flatMap(next(_, c)) def nextss(qs: Set[A], s: List[C]) : Set[A] = s match { case Nil => ecl(qs) case c::cs => nextss(ecl(nexts(ecl(qs), c)), cs) } def accepts(s: List[C]) : Boolean = nextss(starts, s.toList).exists(fins)}val etrans1 = Set[Edge[State, Option[Char]]]( { case (Q0, Some('a')) => Q1 }, { case (Q1, None) => Q0 })val enfa = eNFA(Set[State](Q0), etrans1, Set[State](Q1))enfa.accepts("a".toList) // trueenfa.accepts("".toList) // falseenfa.accepts("aaaaa".toList) // trueenfa.accepts("aaaaab".toList) // flaseenfa.accepts("aaaaabbb".toList) // falseenfa.accepts("aaaaabbbaaa".toList) // falseenfa.accepts("ac".toList) // falseabstract class Rexpcase object ZERO extends Rexpcase object ONE extends Rexpcase class CHAR(c: Char) extends Rexpcase object ALL extends Rexpcase class ALT(r1: Rexp, r2: Rexp) extends Rexp case class SEQ(r1: Rexp, r2: Rexp) extends Rexp case class STAR(r: Rexp) extends Rexp case class NTIMES(r: Rexp, n: Int) extends Rexp case class UPNTIMES(r: Rexp, n: Int) extends Rexp import scala.language.implicitConversions import scala.language.reflectiveCalls def charlist2rexp(s: List[Char]): Rexp = s match { case Nil => ONE case c::Nil => CHAR(c) case c::s => SEQ(CHAR(c), charlist2rexp(s))}implicit def string2rexp(s: String): Rexp = charlist2rexp(s.toList)implicit def RexpOps (r: Rexp) = new { def | (s: Rexp) = ALT(r, s) def % = STAR(r) def ~ (s: Rexp) = SEQ(r, s)}implicit def stringOps (s: String) = new { def | (r: Rexp) = ALT(s, r) def | (r: String) = ALT(s, r) def % = STAR(s) def ~ (r: Rexp) = SEQ(s, r) def ~ (r: String) = SEQ(s, r)}// nullable function: tests whether the regular // expression can recognise the empty stringdef nullable (r: Rexp) : Boolean = r match { case ZERO => false case ONE => true case CHAR(_) => false case ALL => false case ALT(r1, r2) => nullable(r1) || nullable(r2) case SEQ(r1, r2) => nullable(r1) && nullable(r2) case STAR(_) => true case NTIMES(r, i) => if (i == 0) true else nullable(r) case UPNTIMES(r: Rexp, n: Int) => true}// derivative of a regular expression w.r.t. a characterdef der (c: Char, r: Rexp) : Rexp = r match { case ZERO => ZERO case ONE => ZERO case CHAR(d) => if (c == d) ONE else ZERO case ALL => ONE case ALT(r1, r2) => ALT(der(c, r1), der(c, r2)) case SEQ(r1, r2) => if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2)) else SEQ(der(c, r1), r2) case STAR(r1) => SEQ(der(c, r1), STAR(r1)) case NTIMES(r1, i) => if (i == 0) ZERO else if (nullable(r1)) SEQ(der(c, r1), UPNTIMES(r1, i - 1)) else SEQ(der(c, r1), NTIMES(r1, i - 1)) case UPNTIMES(r1, i) => if (i == 0) ZERO else SEQ(der(c, r1), UPNTIMES(r1, i - 1)) }// partial derivative of a regular expression w.r.t. a characterdef pder (c: Char, r: Rexp) : Set[Rexp] = r match { case ZERO => Set() case ONE => Set() case CHAR(d) => if (c == d) Set(ONE) else Set() case ALL => Set(ONE) case ALT(r1, r2) => pder(c, r1) ++ pder(c, r2) case SEQ(r1, r2) => (for (pr1 <- pder(c, r1)) yield SEQ(pr1, r2)) ++ (if (nullable(r1)) pder(c, r2) else Set()) case STAR(r1) => for (pr1 <- pder(c, r1)) yield SEQ(pr1, STAR(r1)) case NTIMES(r1, i) => if (i == 0) Set() else if (nullable(r1)) for (pr1 <- pder(c, r1)) yield SEQ(pr1, UPNTIMES(r1, i - 1)) else for (pr1 <- pder(c, r1)) yield SEQ(pr1, NTIMES(r1, i - 1)) case UPNTIMES(r1, i) => if (i == 0) Set() else for (pr1 <- pder(c, r1)) yield SEQ(pr1, UPNTIMES(r1, i - 1))}val r = STAR(ALL) ~ "a" ~ NTIMES(ALL, 3) ~ "bc"val pder_nfa = NFA[Set[Rexp], Char](Set(Set(r)), Set( { case (rs, c) => rs.flatMap(pder(c, _))} ), _.exists(nullable))pder_nfa.accepts("axaybzbc".toList) // truepder_nfa.accepts("aaaaxaybzbc".toList) // truepder_nfa.accepts("axaybzbd".toList) // false///type Trans[A, C] = Map[(A, C), A]