{- | Functions for constructing a simplified regular expression. -} module FST.RegTypes ( -- * Type classes Combinators ( (<|>), (|>), star, plus, empty ), Symbols (symbols), -- * Types Reg(..), -- * Combinators (<&>), (<->), complement, reversal, allFree, -- * Constructors s, eps, allS, allToSymbols, -- * Query functions acceptEps, ) where import Data.List (nub) -- | Data type for a regular expression. data Reg a = Empty -- ^ [ ] | Epsilon -- ^ 0 | All -- ^ ? | Symbol a -- ^ a | Reg a :|: Reg a -- ^ [ r1 | r2 ] | Reg a :.: Reg a -- ^ [ r1 r2 ] | Reg a :&: Reg a -- ^ [ r1 & r2 ] | Complement (Reg a) -- ^ ~[ r1 ] | Star (Reg a) -- ^ [ r2 ]* deriving (Eq) infixl 4 <|> -- Union infixl 5 |> -- Concatenation infixl 3 <&> -- Intersection infixl 3 <-> -- Set minus -- | Combinators. The regular expressions are simplified while combined. class Combinators a where (<|>) :: a -> a -> a -- ^ Union (|>) :: a -> a -> a -- ^ Concatenation star :: a -> a -- ^ Kleene's star plus :: a -> a -- ^ Kleene's plus empty :: a -- ^ Empty language instance Eq a => Combinators (Reg a) where Empty <|> b = b -- [ [] | r1 ] = r1 a <|> Empty = a -- [ r1 | [] ] = r1 _ <|> Star All = Star All Star All <|> _ = Star All a@(a1 :.: a2) <|> b@(b1 :.: b2) | a == b = a | a1 == b1 = a1 |> (a2 <|> b2) | a2 == b2 = (a1 <|> b1) |> a2 | otherwise = a :|: b a <|> b = if a == b then a else a :|: b -- [ r1 | r1 ] = r1 Empty |> _ = empty -- [ [] r1 ] = [] _ |> Empty = empty -- [ r1 [] ] = [] Epsilon |> b = b -- [ 0 r1 ] = r1 a |> Epsilon = a -- [ r1 0 ] = r1 a |> b = a :.: b star (Star a) = star a -- [r1]** = [r1]* star (Epsilon) = eps -- [0]* = 0 star (Empty) = eps -- [ [] ]* = 0 star a = Star a plus a = a |> star a empty = Empty -- | Intersection (<&>) :: Eq a => Reg a -> Reg a -> Reg a _ <&> Empty = Empty -- [ r1 & [] ] = [] Empty <&> _ = Empty -- [ [] & r1 ] = [] Star All <&> a = a a <&> Star All = a a <&> b | a == b = a -- [ r1 & r1 ] = r1 | otherwise = a :&: b -- | Minus. Definition A - B = A & ~B (<->) :: Eq a => Reg a -> Reg a -> Reg a Empty <-> _ = empty -- [ [] - r1 ] = [] a <-> Empty = a -- [ r1 - [] ] = r1 a <-> b | a == b = empty -- [ r1 - r1 ] = [] | otherwise = a <&> (complement b) -- | Symbol s :: a -> Reg a s a = Symbol a -- | Epsilon eps :: Reg a eps = Epsilon -- | All symbol allS :: Reg a allS = All -- | Complement complement :: Eq a => Reg a -> Reg a complement Empty = star allS -- ~[ [] ] = ?* complement Epsilon = plus allS -- ~[ 0 ] = [? ?*] complement (Star All) = empty complement (Complement a) = a complement a = Complement a -- | Transform the 'all' symbol to union over alphabet. ? -> [a|..] with respect to an alphabet [a] allToSymbols :: Eq a => [a] -> Reg a allToSymbols [] = empty allToSymbols ys = foldr1 (:|:) (map s ys) -- | Construct a ?-free regular expression with respect to an alphabet [a] allFree :: Eq a => Reg a -> [a] -> Reg a allFree (a :|: b) sigma = allFree a sigma :|: allFree b sigma allFree (a :.: b) sigma = allFree a sigma :.: allFree b sigma allFree (a :&: b) sigma = allFree a sigma :&: allFree b sigma allFree (Complement a) sigma = Complement (allFree a sigma) allFree (Star a) sigma = Star (allFree a sigma) allFree All sigma = allToSymbols sigma allFree r _ = r -- | Reverse the language denoted by the regular expression. reversal :: Eq a => Reg a -> Reg a reversal (a :|: b) = reversal a :|: reversal b reversal (a :.: b) = reversal b :.: reversal a reversal (a :&: b) = reversal a :&: reversal b reversal (Complement a) = Complement (reversal a) reversal (Star a) = Star (reversal a) reversal r = r -- | Examines if a regular expression accepts the empty string. acceptEps :: Eq a => Reg a -> Bool acceptEps Epsilon = True acceptEps (Star _) = True acceptEps (a :|: b) = acceptEps a || acceptEps b acceptEps (a :.: b) = acceptEps a && acceptEps b acceptEps (a :&: b) = acceptEps a && acceptEps b acceptEps (Complement a) = not (acceptEps a) acceptEps _ = False -- | Type class for the collection of symbols in an expression. class Symbols f where symbols :: Eq a => f a -> [a] -- ^ Collect the symbols in a regular expression. instance Symbols Reg where symbols (Symbol a) = [a] symbols (a :.: b) = nub (symbols a ++ symbols b) symbols (a :|: b) = nub (symbols a ++ symbols b) symbols (a :&: b) = nub (symbols a ++ symbols b) symbols (Complement a) = symbols a symbols (Star a) = symbols a symbols _ = [] instance Show a => Show (Reg a) where show Empty = "[0 - 0]" show Epsilon = "0" show (Symbol a) = show a show All = "?" show (Complement a) = "~[" ++ show a ++ "]" show (Star a) = "[" ++ show a ++ "]* " show (a :|: b) = "[" ++ show a ++ " | " ++ show b ++ "]" show (a :.: b) = "[" ++ show a ++ " " ++ show b ++ "]" show (a :&: b) = "[" ++ show a ++ " & " ++ show b ++ "]"