{- Syntax Implementieren Sie den AST (abstract syntax tree) entsprechend den Vorgaben auf dem Übungsblatt. -} data Regex = Empty | Epsilon | Symbol Char | Sequence Regex Regex | Star Regex | Choice Regex Regex -- | Sequence, Star, Choice fehlen noch. deriving Show {- Semantik Ziel ist es die Funktion 'match :: Regex -> String -> Bool' zu implementieren, die überprüft ob ein gegebener String zu einer gegebenen Regex passt. Im folgenden werden dafür zuerst drei Hilfsfunktionen implementiert, die Sie dann für 'match' verwenden können. -} {- Helper function 1: Given a predicate and a string this function returns all (proper) tails of the string that are obtained by removing an initial segment that satisfies the predicate. Examples: tails (\s -> length s == 1) "abcde" == ["bcde"] tails (\s -> length s >= 1) "abcde" == ["bcde","cde","de","e",""] -} tails :: (String -> Bool) -> String -> [String] tails f s = concatMap (\x -> if f (take x s) then [(drop x s)] else []) [0..(length s)] -- >>> tails (\s -> length s >= 1) "abcde" -- ["bcde","cde","de","e",""] -- {- Helper function 2: By repeatedly calling the tails function, this function checks if it is possible to partition a given string into consecutive segments each of which satisfies the predicate. Examples: segmentable (\s -> length s == 2) "abcde" == False segmentable (\s -> length s == 2) "abcd" == True -} segmentable :: (String -> Bool) -> String -> Bool segmentable f s | s == "" = True | "" `elem` leads = True | leads == [] = False | otherwise = or (map (\x -> segmentable f x) leads) where leads = tails f s -- >>> segmentable (\s -> length s == 2) "abcde" -- False -- -- >>> segmentable (\s -> length s == 2) "abcd" -- True -- {- Helper function 3: Given two predicates and a string, this function checks if it is possible to partition the string into a prefix and a suffix such that the prefix satisfies the first predicate and the suffix satisfies the second predicate. Examples: combinable (\s -> length s == 2) (\s -> length s == 3) "12345" == True combinable (\s -> length s == 2) (\s -> length s == 3) "1234" == False combinable (\s -> length s == 2) (\s -> length s == 3) "123456" == False -} combinable :: (String -> Bool) -> (String -> Bool) -> String -> Bool combinable f g s = or ( map (\x -> f (take x s) && g (drop x s)) (reverse [0..len]) ) where len = length s -- >>> combinable (\s -> length s == 2) (\s -> length s == 3) "12345" -- >>> combinable (\s -> length s == 2) (\s -> length s == 3) "1234" -- >>> combinable (\s -> length s == 2) (\s -> length s == 3) "123456" -- True -- False -- False -- {- Matching a particular string to a regex a regex now simply means to check to cover the base cases and use the helper functions. -} match :: Regex -> String -> Bool match r s = case r of Empty -> s == "" Epsilon -> False Symbol c -> s == [c] Choice r1 r2 -> (match r1 s || match r2 s) Sequence r1 r2 -> combinable (match r1) (match r2) s Star r1 -> segmentable (match r1) s {- Examples/test-cases -} -- (ab*|ac*)* r1 :: Regex r1 = Star ( Choice ( Sequence ( Symbol 'a') ( Star (Symbol 'b')) ) (Sequence (Symbol 'a') (Star (Symbol 'c')) ) ) -- (ab*|ac*)*x* r2 :: Regex r2 = Sequence r1 (Star (Symbol 'x')) -- ab r3 :: Regex r3 = Sequence (Symbol 'a') (Symbol 'b') -- a(a|b)* r4 :: Regex r4 = Sequence (Symbol 'a') $ Star $ Choice (Symbol 'a') (Symbol 'b') shouldBeTrue1 :: Bool shouldBeTrue1 = match r1 "abbbbaccca" -- >>> match r1 "abbbbaccca" -- True -- shouldBeFalse1 :: Bool shouldBeFalse1 = match r1 "abbcc" -- >>> match r1 "abbcc" -- False -- shouldBeTrue2 :: Bool shouldBeTrue2 = match r2 "abbbbacccabxxxx" -- >>> match r2 "abbbbacccabxxxx" -- True -- shouldBeFalse2 :: Bool shouldBeFalse2 = match r2 "abbxxxacc" -- >>> match r2 "abbxxxacc" -- False -- shouldBeTrue3 :: Bool shouldBeTrue3 = match r3 "ab" -- >>> match r3 "ab" -- True -- shouldBeFalse3 :: Bool shouldBeFalse3 = match r3 "aba" -- >>> match r3 "aba" -- False -- shouldBeTrue4 :: Bool shouldBeTrue4 = match r4 "abbbab" -- >>> match r4 "abbbab" -- True -- shouldBeFalse4 :: Bool shouldBeFalse4 = match r4 "abbabc" -- >>> match r4 "abbabc" -- False --