moreReduce :: RE -> RE
moreReduce r = if go r' == r' then r' else moreReduce (go r')
    where r' = reduce r
          go r@(Plus a b)
            | a `contain` b = a
            | b `contain` a = b
            | otherwise = (go a) `Plus` (go b)
          go r@(Concat a b)
            | a `contain` Epsilon && b `contain` a && isClosure b = b
            | b `contain` Epsilon && a `contain` b && isClosure a = a
            | otherwise = foldl (\x y -> (go x) `Concat` (go y)) (head rs) (tail rs)
                where rs = concatListReduce (concatToList r)
          go (Closure k)
            | isPlus k && k `contain` Epsilon = Closure (removeEpsilon k)
            | otherwise = Closure (go k)
          go k = k
          concatToList (Concat a b) = concatToList a ++ concatToList b
          concatToList k = [k]
          concatReduce r@(Concat a b)
            | a `contain` Epsilon && b `contain` a && isClosure b = b
            | b `contain` Epsilon && a `contain` b && isClosure a = a
            | otherwise = r
          concatListReduce [] = []
          concatListReduce [a] = [a]
          concatListReduce (a:b:l) = if rab == ab then a:concatListReduce (b:l) else rab:concatListReduce l
            where ab = a `Concat` b
                  rab = concatReduce ab
moreReduce :: RE -> RE
moreReduce r = if go r' == r' then r' else moreReduce (go r')
    where r' = reduce r
          go r@(Plus a b)
            | a `contain` b = a
            | b `contain` a = b
            | otherwise = (go a) `Plus` (go b)
          go r@(Concat a b)
            | a `contain` Epsilon && b `contain` a && isClosure b = b
            | b `contain` Epsilon && a `contain` b && isClosure a = a
            | otherwise = foldl (\x y -> (go x) `Concat` (go y)) (head rs) (tail rs)
                where rs = concatListReduce (concatToList r)
          go (Closure k)
            | isPlus k && k `contain` Epsilon = Closure (removeEpsilon k)
            | otherwise = Closure (go k)
          go k = k
          concatToList (Concat a b) = concatToList a ++ concatToList b
          concatToList k = [k]
          concatReduce r@(Concat a b)
            | a `contain` Epsilon && b `contain` a && isClosure b = b
            | b `contain` Epsilon && a `contain` b && isClosure a = a
            | otherwise = r
          concatListReduce [] = []
          concatListReduce [a] = [a]
          concatListReduce (a:b:l) = if rab == ab then a:concatListReduce (b:l) else rab:concatListReduce l
            where ab = a `Concat` b
                  rab = concatReduce ab
moreReduce r = if go r' == r' then r' else moreReduce (go r')
    where r' = reduce r
          go r@(Plus a b)
            | a `contain` b = a
            | b `contain` a = b
            | otherwise = (go a) `Plus` (go b)
          go r@(Concat a b)
            | a `contain` Epsilon && b `contain` a && isClosure b = b
            | b `contain` Epsilon && a `contain` b && isClosure a = a
            | otherwise = foldl (\x y -> (go x) `Concat` (go y)) (head rs) (tail rs)
                where rs = concatListReduce (concatToList r)
          go (Closure k)
            | isPlus k && k `contain` Epsilon = Closure (removeEpsilon k)
            | otherwise = Closure (go k)
          go k = k
          concatToList (Concat a b) = concatToList a ++ concatToList b
          concatToList k = [k]
          concatReduce r@(Concat a b)
            | a `contain` Epsilon && b `contain` a && isClosure b = b
            | b `contain` Epsilon && a `contain` b && isClosure a = a
            | otherwise = r
          concatListReduce [] = []
          concatListReduce [a] = [a]
          concatListReduce (a:b:l) = if rab == ab then a:concatListReduce (b:l) else rab:concatListReduce l
            where ab = a `Concat` b
                  rab = concatReduce ab