import Data.List (elemIndex, tails) import Data.Maybe (fromJust) doLZW :: Eq a => [a] -> [a] -> [Int] doLZW _ [] = [] doLZW as (x:xs) = lzw (return <$> as) [x] xs where lzw a w [] = [fromJust $ elemIndex w a] lzw a w (x:xs) | w_ `elem` a = lzw a w_ xs | otherwise = fromJust (elemIndex w a) : lzw (a ++ [w_]) [x] xs where w_ = w ++ [x] undoLZW :: [a] -> [Int] -> [a] undoLZW _ [] = [] undoLZW a cs = cs >>= (!!) (foldl ((.) <$> (++) <*> (\x xs -> return (((++) <$> head <*> take 1 . last) ((x !!) <$> xs)))) (return <$> a) (take2 cs)) take2 :: [a] -> [[a]] take2 xs = filter ((2 ==) . length) (take 2 <$> tails xs) main :: IO () main = do print $ doLZW ['\0' .. '\255'] "TOBEORNOTTOBEORTOBEORNOT" print $ undoLZW ['\0' .. '\255'] [84, 79, 66, 69, 79, 82, 78, 79, 84, 256, 258, 260, 265, 259, 261, 263] print $ ((==) <*> ((.) <$> undoLZW <*> doLZW) ['\NUL' .. '\255']) "TOBEORNOTTOBEORTOBEORNOT"