Haskell でオートマトン(6)

Dfa をさらに書き直してよりエレガント?にした。

  • 状態遷移関数は結局、lookup するだけだった
  • インスタンスを生成するための関数を追加した
  • union をより簡潔に。
module Fa where
import qualified Test.HUnit as Test
-- import System.Environment

data State = State String | State2 (State, State) deriving (Eq, Show)
type Symbol = Char
type Alphabet = [Symbol]

-- Dfa states alphabet transition-function "start state" "accept states"
data Dfa = Dfa [State] Alphabet [((State, Symbol), State)] State [State] deriving (Show, Eq)

transitFa alist s0 c0 = case lookup (s0, c0) alist of
                          Just s -> s
                          Nothing -> error "Invalid transition."

makeDfa qs cs tr st as = if (checkStart && checkAccept && and (map checkTransit tr)) then
                             Dfa qs cs tr st as
                         else
                             error "Fail to makeDfa: Invalid data."
                         where
                           checkStart = (elem st qs)
                           checkAccept = all (\x -> elem x qs) as
                           checkTransit ((s, c), n) = and [elem s qs, elem c cs, elem n qs]

accept :: Dfa -> [Symbol] -> Bool

accept (Dfa qs cs tr st as) str = accept' st str
    where
      accept' s [] = elem s as
      accept' s (c:cs) = accept' (transitFa tr s c) cs

union :: Dfa -> Dfa -> Dfa
--union = undefined
union (Dfa qs1 c1 tr1 s1 as1) (Dfa qs2 c2 tr2 s2 as2) = Dfa states alphabet transit start accept 
    where
      states = [ State2 (r1, r2) | r1 <- qs1, r2 <- qs2 ]
      alphabet = c1 -- fixme
      start = State2 (s1, s2)
      accept = [ State2 (r1, r2) | r1 <- qs1, r2 <- qs2, (elem r1 as1) || (elem r2 as2)]
      transit = [ ((State2 (r1, r2), a),
                   State2 (transitFa tr1 r1 a, transitFa tr2 r2 a))
                  | r1 <- qs1, r2 <- qs2, a <- alphabet]