-
Notifications
You must be signed in to change notification settings - Fork 1
/
FiniteStateAutomata.hs
153 lines (129 loc) · 4.62 KB
/
FiniteStateAutomata.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{-# LANGUAGE TypeFamilies, FlexibleContexts,FlexibleInstances, ConstrainedClassMethods #-}
module FiniteStateAutomata(
FSA(..),
NFA'(..),
NFAMap,
DFA'(..),
DFAMap,
epsilon, ppfsa) where
import qualified Data.Map as M
import qualified Data.Set as S
class (Ord (Alpha f),
Show (Alpha f),
Show f,
Show (FSAVal f),
Listable (FSAVal f)) => FSA f where
type Alpha f
type FSAVal f
alphabet :: (Ord (Alpha f), Show (Alpha f)) =>
f -> S.Set (Alpha f)
accepting :: f -> S.Set Int
start :: f -> Int
trans :: f -> M.Map Int (FSAVal f)
states :: f -> S.Set Int
states fsa = S.unions [(S.fromList . M.keys . trans $ fsa),
(accepting fsa),
(S.fromList .
concatMap sndList .
M.elems . trans $ fsa)]
data DFA' a = DFA' {alpha :: S.Set a,
ss :: DFAMap a,
accept :: S.Set Int,
st :: Int} deriving (Show, Read, Eq)
data NFA' a = NFA' {nalpha :: S.Set a,
nss :: NFAMap a,
naccept :: S.Set Int,
nst :: Int}
type DFAMap a = M.Map Int (M.Map a Int)
type NFAMap a = M.Map Int (S.Set (Maybe a, Int))
class (Show (Elem m)) => Listable m where
type Elem m
toList :: m -> [(Elem m,Int)]
instance (Show a) => Listable (M.Map a Int) where
type Elem (M.Map a Int) = a
toList = M.toList
instance (Show a) => Listable (S.Set (Maybe a, Int)) where
type Elem (S.Set (Maybe a, Int)) = Maybe a
toList = S.toList
sndList :: Listable m => m -> [Int]
sndList = map snd . toList
fsaShow :: (FSA f) => f -> String
fsaShow fsa = "{alphabet="
++ (show . S.toList . alphabet $ fsa)
++ "," ++
"states=" ++
(show . S.toList . states $ fsa) ++ "," ++
"start=" ++ (show . start $ fsa) ++ "," ++
"accepting="
++ (show . S.toList . accepting $ fsa)
++ "," ++ "trans="
++ (show . map (filter (/= '"')) .
showTransitions $ fsa)
pettyPrinter :: (FSA f) => f -> IO ()
pettyPrinter fsa = (putStr $ "alphabet="
++ (show . S.toList . alphabet $ fsa)
++ "\n" ++
"states="
++ (show . S.toList . states $ fsa)
++ "\n" ++
"start=" ++ (show . start $ fsa)
++ "\n" ++
"accepting="
++ (show . S.toList . accepting $ fsa)
++ "\n") >> trans
where trans =
mapM_ (putStrLn . filter (/= '"'))
$ showTransitions fsa
ppfsa :: (FSA f) => f -> IO ()
ppfsa = pettyPrinter
showTransitions :: (FSA f) => f -> [String]
showTransitions fsa = map showTransition .
M.toList . trans $ fsa where
showTransition (from, ts) = (show from)
++ " :: "
++ (show . map showTransition' . toList $ ts) where
showTransition' (x, to) = (show x) ++ " -> " ++ (show to)
instance (Ord a, Show a) => FSA (DFA' a) where
type Alpha (DFA' a) = a
type FSAVal (DFA' a) = (M.Map a Int)
alphabet = alpha
accepting = accept
start = st
trans = ss
epsilon :: Maybe a
epsilon = Nothing
instance (Ord a, Show a) => FSA (NFA' a) where
type Alpha (NFA' a) = a
type FSAVal (NFA' a) = (S.Set (Maybe a, Int))
alphabet = nalpha
accepting = naccept
start = nst
trans = nss
instance (Ord a, Show a) => Show (NFA' a) where
show nfa = "NFA " ++ (fsaShow nfa)
simpleNFA :: NFA' Char
simpleNFA = NFA' alpha states accepting start where
alpha = S.fromList ['a','b']
states = M.fromList
[(0, S.fromList [(Just 'a', 1)]),
(1, S.fromList [(Just 'b', 0), (epsilon, 2)])]
start = 0
accepting = S.fromList [2]
simpleDFA :: DFA' Char
simpleDFA = DFA' alpha states accepting start where
alpha = S.fromList ['a','b','c']
states = M.fromList
[(0, M.fromList [('a', 1)]),
(1, M.fromList [('b', 0), ('c', 2)])]
start = 0
accepting = S.fromList [2]
deadStateDFA :: DFA' Char
deadStateDFA = DFA' alpha states accepting start where
alpha = S.fromList "ab"
states =
M.fromList [(0, trans0), (1, trans1), (2, trans2)] where
trans0 = M.fromList [('a', 1), ('b', 2)]
trans1 = M.fromList [('b', 3)]
trans2 = M.fromList [('a', 3)]
accepting = S.fromList [1, 2]
start = 0