如何改进这些haskell压缩和解压缩功能



指定通过将相同的连续元素转换为按元素对的数字来压缩列表的函数。组函数可能很有用。

指定从压缩列表中恢复原始文件的函数。复制功能可能很有用。

import Data.List

compress :: (Eq a, Integral b) => [a] -> [(b, a)]
compress l = zip (length $ group l) (head $ group l)
Or:
compress :: (Eq a, Integral b) => [a] -> [(b, a)]
compress [] = []
compress (x:xs) 
| x == a = (b+1,a) : xs
| otherwise = (1,a) : compress (b,a) xs

decompress :: (Eq a, Integral b) => [(b, a)] -> [a]
decompress l = concat [replicate (fst x) (snd x) | x <- l]

Examples:
compress "aaaabccaadeeee" == [(4, 'a'), (1, 'b'), (2, 'c'), (2, 'a'), (1, 'd'), (4, 'e')]
compress "oh hello !!" == [(1, 'o'), (1, 'h'), (1, ''), (1, 'h'), (1, 'e'), (2, 'l'), (1, 'o'), (2, '!')]
compress [] == []
compress [1,1,0,0,0,1,1,1] == [(2.1), (3.0), (3.1)]
decompress [(4, 'a'), (1, 'b'), (2, 'c'), (2, 'a'), (1, 'd'), (4, 'e')] == "aaaabccaadeeee"
decompress [(1, 'o'), (1, 'h'), (1, ''), (1, 'h'), (1, 'e'), (2, 'l'), ( 1, 'o'), (2, '!')] == "oh hello !!"
decompress [] == []
decompress [(2,1), (3,0), (3,1)] == [1,1,0,0,0,1,1,1]

您在这里对group的结果进行了两次枚举。您可以简化此过程,并使用映射函数将组结果的每个项转换为2元组,例如使用(&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')length :: Foldable f => f a -> Int返回一个Int,因此不能使用任何Integral类型:

import Control.Arrow((&&&))
compress :: Eq a => [a] -> [(Int, a)]
compress = map (length &&& head) . group

对于解压缩,我们可以使用concatMap :: Foldable t => (a -> [b]) -> t a -> [b]并使用uncurry :: (a -> b -> c) -> (a, b) -> c来创建一个适用于2元组的replicate变体replicate :: Int -> a -> [a]适用于Int,而不是任何Integral,并且Eq类型约束在这里是而不是必需的,因为我们可以复制任何项。concatMap可以在任何Foldable上工作,因此我们可以将类型签名推广为:

decompress :: Foldable f => f (Int, a) -> [a]
decompress = concatMap (uncurry replicate)

最新更新