Guest User

Untitled

a guest
Jan 8th, 2018
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE DeriveFunctor #-}
  2.  
  3. module Kata.BraceExpansion (expandBraces) where
  4.  
  5. import Control.Applicative
  6. import Control.Arrow
  7. import Control.Monad
  8. import Data.Array (Ix(..), inRange)
  9. import Data.List
  10. import Data.List.Split
  11. import Data.Maybe
  12.  
  13. expandBraces :: String -> [String]
  14. expandBraces = expandParsed . reverse . process
  15.  
  16. expandParsed :: [Parse Char] -> [String]
  17. expandParsed [] = [[]]
  18. expandParsed (x:xs) =
  19.   case x of
  20.     ParseSimple s -> map (s ++) $ expandParsed xs
  21.     ParseGroup gr -> [g ++ s  | g <- expandGroup gr, s <- expandParsed xs]
  22.  
  23. expandGroup :: Group Char -> [String]
  24. expandGroup [] = []
  25. expandGroup (End:rest) = expandGroup rest
  26. expandGroup (G g rest:restg) =
  27.   (liftA2 (++) (expandGroup g) (expandGroupItem rest)) ++ (expandGroup restg)
  28. expandGroup (S s rest:restg) =
  29.   (map (s ++) (expandGroupItem rest)) ++ (expandGroup restg)
  30.  
  31. expandGroupItem :: GroupItem Char -> [String]
  32. expandGroupItem End = [[]]
  33. expandGroupItem (S s rest) = map (s ++) $ expandGroupItem rest
  34. expandGroupItem (G g rest) = liftA2 (++) (expandGroup g) (expandGroupItem rest)
  35.  
  36.  
  37. data Parse a
  38.   = ParseSimple [a]
  39.   | ParseGroup (Group a)
  40.   deriving (Show)
  41.  
  42. type Group a = [GroupItem a]
  43.  
  44. data GroupItem a
  45.   = End
  46.   | S [a]
  47.       (GroupItem a)
  48.   | G (Group a)
  49.       (GroupItem a)
  50.   deriving (Functor, Show)
  51.  
  52. data Token
  53.   = Open !Int
  54.   | Close !Int
  55.   | Non !Char !Int
  56.   | Separator !Int
  57.   deriving (Eq, Show)
  58.  
  59. biggestGroups :: Ix a => [(a, a)] -> [(a, a)]
  60. biggestGroups [] = []
  61. biggestGroups [y] = [y]
  62. biggestGroups (x:y:xs) =
  63.   if uncurry (&&) . (join (***)) (inRange x) $  y
  64.     then biggestGroups (x:xs)
  65.     else x : biggestGroups (y:xs)
  66.  
  67.  
  68. process :: String -> [Parse Char]
  69. process str =
  70.   let xs = convert str
  71.       matches = findMatches xs
  72.       bigs = biggestGroups matches
  73.   in cleanup $ foldr
  74.                 (\(open, close) (list, ts) ->
  75.                    let before = takeWhile ((< open) . tokenindex) ts
  76.                        after = dropWhile ((<= close) . tokenindex) ts
  77.                        gr =
  78.                          takeWhile ((< close) . tokenindex) .
  79.                          dropWhile ((<= open) . tokenindex) $
  80.                          ts
  81.                        withins = withinGroups (open, close) matches
  82.                    in ( (ParseGroup $
  83.                          (map (fmap backToChar) $
  84.                           processGroup gr (delete (open, close) withins))) :
  85.                         ParseSimple (map backToChar before) : list
  86.                       , after))
  87.                 ([], xs)
  88.                 (reverse bigs)
  89.   where
  90.     cleanup (parsed, leftover) =
  91.       (ParseSimple $ map backToChar leftover) : parsed
  92.  
  93. processGroup :: [Token] -> [(Int, Int)] -> Group Token
  94. processGroup ts bnds =
  95.   let separators =
  96.         mapMaybe
  97.           (\x ->
  98.              case isSep x of
  99.                Just i ->
  100.                  if any (`inRange` i) bnds
  101.                    then if null bnds
  102.                            then Just i
  103.                            else Nothing
  104.                    else Just i
  105.                Nothing -> Nothing)
  106.           ts
  107.       splits = splitWhen (flip elem separators . tokenindex) ts
  108.   in map (go End) splits
  109.   where
  110.     go b a =
  111.       if all isNon a
  112.         then S a b
  113.         else case find isOpen a of
  114.                Just (Open o) ->
  115.                  case snd <$> find ((== o) . fst) bnds of
  116.                    Just c ->
  117.                      case span ((< o) . tokenindex) a of
  118.                        (us, vs) ->
  119.                          case (second (drop 1) $ span ((< c) . tokenindex) (drop 1 vs)) of
  120.                            (uss, vss) ->
  121.                              let withins = delete (o, c) (withinGroups (o, c) bnds)
  122.                                  gr = processGroup uss withins
  123.                              in if null us
  124.                                    then (if null vss
  125.                                            then G gr b
  126.                                            else G gr (go b vss))
  127.                                    else if null vss
  128.                                            then S us (G gr b)
  129.                                            else S us (G gr (go b vss))
  130.                    _ -> undefined
  131.                _ -> undefined
  132.  
  133. isOpen :: Token -> Bool
  134. isOpen (Open _) = True
  135. isOpen _ = False
  136.  
  137. isNon :: Token -> Bool
  138. isNon (Non _ _) = True
  139. isNon _ = False
  140.  
  141. isSep :: Token -> Maybe Int
  142. isSep (Separator i) = Just i
  143. isSep _ = Nothing
  144.  
  145. tokenindex :: Token -> Int
  146. tokenindex (Open i) = i
  147. tokenindex (Close i) = i
  148. tokenindex (Non _ i) = i
  149. tokenindex (Separator i) = i
  150.  
  151. backToChar :: Token -> Char
  152. backToChar t =
  153.   case t of
  154.     Non c _ -> c
  155.     Separator _ -> ','
  156.     _ -> error "backToChar: You should not get here"
  157.  
  158. stripNon :: Token -> Char
  159. stripNon (Non c _) = c
  160. stripNon _ = error "stripNon:error"
  161.  
  162. withinGroups :: Ix a => (a, a) -> [(a, a)] -> [(a, a)]
  163. withinGroups x xs = filter (uncurry (&&) . (join (***)) (inRange x)) xs
  164.  
  165. convert :: String -> [Token]
  166. convert =
  167.   snd .
  168.   mapAccumL
  169.     (\i c ->
  170.        case (c == '{', c == '}') of
  171.          (True, False) -> (succ i, (Open i))
  172.          (False, True) -> (succ i, (Close i))
  173.          _ ->
  174.            if c == ','
  175.              then (succ i, Separator i)
  176.              else (succ i, Non c i))
  177.     0
  178.  
  179. findMatches :: [Token] -> [(Int, Int)]
  180. findMatches xs =
  181.   catMaybes [findMatchingParen x (drop 1 $ dropWhile (/= x) xs) | x <- xs]
  182.  
  183. findMatchingParen :: Token -> [Token] -> Maybe (Int, Int)
  184. findMatchingParen (Open open) xs = go (0 :: Int) xs
  185.   where
  186.     go _ [] = Nothing
  187.     go i (y:ys) =
  188.       case y of
  189.         Non _ _ -> go i ys
  190.         Separator _ -> go i ys
  191.         Open _ -> go (i + 1) ys
  192.         (Close close) ->
  193.           if i == 0
  194.             then Just (open, close)
  195.             else go (pred i) ys
  196. findMatchingParen _ _ = Nothing
Advertisement
Add Comment
Please, Sign In to add comment