NFA -> DFA (2)
さらに書き換えて、よりDFA,NFA の定義通りにして、よりHaskellらしくできた、つもり。
- 状態 State 型は型変数を取ることにした。これで文字からなる状態も、状態の対からなる状態も、 Data.Set 、つまり集合からなる状態も、同じように扱える。
- 同じく、文字 Symbol 型も型変数を取ることにした。
- 新しい定義では、状態遷移関数は文字通り、関数になった。Dfa と Nfa は、この状態遷移関数の型が違う。Dfa は状態と文字を受け取り状態を返す。Nfa は同じく状態と文字を受け取るが、状態の集合を返す。
-- DFA の状態遷移関数 type Delta a b = State a -> Symbol b -> State a -- NFA の状態遷移関数 type Delta' a b = State a -> Symbol b -> States a
- Dfa の合成は、同じアルファベットのときしか定義していない。違う場合はどうするのだろう?よく分かっていない。存在しない文字に対する遷移先、というものは定義できない気がするのだが。
- 小さな修正として、可能な限り Data.Set のメソッドを利用した。まだ使えるところもあるかもしれない。
module Fa where import qualified Test.HUnit as Test import qualified Data.Set as Set -- DFA は5つ組である -- 状態の集合 Q -- '文字'の集合 Σ -- 遷移関数 δ: Q × Σ → Q -- 開始状態 q0 -- 終了状態の集合 F (Q の部分集合) data State a = State a deriving (Eq, Show, Ord) type States a = Set.Set (State a) data Symbol a = Symbol a deriving (Eq, Show, Ord) type Alphabet a = Set.Set (Symbol a) type Delta a b = State a -> Symbol b -> State a type Delta' a b = State a -> Symbol b -> States a data Fa q c = Dfa (States q, Alphabet c, Delta q c, State q, States q) | Nfa (States q, Alphabet c, Delta' q c, State q, States q) statesOf (Dfa (qs, cs, d, q0, fs)) = qs alphabetOf (Dfa (qs, cs, d, q0, fs)) = cs deltaOf (Dfa (qs, cs, d, q0, fs)) = d startOf (Dfa (qs, cs, d, q0, fs)) = q0 acceptOf (Dfa (qs, cs, d, q0, fs)) = fs delta alist = \q c -> case lookup (q, c) alist of Just q' -> q' Nothing -> error ("Invalid transition") delta' alist = \q c -> case lookup (q, c) alist of Just q' -> q' Nothing -> Set.empty accept (Dfa (qs, cs, d, q0, fs)) str = accept' q0 str where accept' q [] = Set.member q fs accept' q (s:ss) = accept' (d q s) ss accept (Nfa (qs, cs, d, q0, fs)) str = accept'' (Set.singleton q0) str where accept'' rs [] = any (\x -> Set.member x fs) (Set.elems rs) accept'' rs (s:ss) = accept'' (Set.unions [ d r s | r <- (Set.elems rs) ] ) ss union (Dfa (qs1, cs1, d1, q1, f1)) (Dfa (qs2, cs2, d2, q2, f2)) | (cs1 == cs2) = Dfa (qs, cs, d, q0, fs) where qs1' = Set.elems qs1 qs2' = Set.elems qs2 qs = Set.fromList [ State (r1, r2) | r1 <- qs1', r2 <- qs2' ] cs = cs1 -- same alphabet q0 = State (q1, q2) fs = Set.fromList [ State (r1, r2) | r1 <- qs1', r2 <- qs2', (Set.member r1 f1) || (Set.member r2 f2)] d = delta [ ((State (r1, r2), a), State (d1 r1 a, d2 r2 a)) | r1 <- qs1', r2 <- qs2', a <- Set.elems cs] powerSet [] = [[]] powerSet (x:xs) = yss ++ map (x:) yss where yss = powerSet xs subset qs = Set.fromList (map (\x -> State (Set.fromList x)) (powerSet (Set.elems qs))) nfaToDfa (Nfa (qs, cs, d, q0, fs)) = Dfa (qs', cs', d', q0', fs') where expand (State s) = Set.elems s isAccept s = any (\x -> Set.member x fs) (expand s) qs' = subset qs cs' = cs unionState ss = State (Set.unions ss) d' = delta [ ((r, c), unionState [d r' c | r' <- expand r ]) | r <- Set.elems qs', c <- Set.elems cs] q0' = State (Set.singleton q0) fs' = Set.filter isAccept qs' dfaToNfa (Dfa (qs, cs, d, q0, fs)) = Nfa (qs', cs', d', q0', fs') where qs' = qs cs' = cs d' = delta' [ ((r, c), Set.singleton (d r c)) | r <- Set.elems qs', c <- Set.elems cs ] q0' = q0 fs' = fs -- accept odd number of a dfa1 = Dfa (Set.fromList [State "q0", State "q1"], -- states Set.fromList (map Symbol "ab"), -- alphabet delta [ ((State "q0", Symbol 'a'), State "q1"), ((State "q0", Symbol 'b'), State "q0"), ((State "q1", Symbol 'a'), State "q0"), ((State "q1", Symbol 'b'), State "q1") ], -- transition function State "q0", -- start state Set.singleton (State "q1")) -- accept states