patternMinor
Run-length encoding in Haskell
Viewed 0 times
lengthhaskellrunencoding
Problem
I wrote a short Haskell script to compress and decompress via the use of run length encoding.
The concept is simple enough,
For example:
As you can see the four consecutive
About the code itself I fear I have written too little points (arguments) to my functions, hindering readability but I am not sure, maybe the lack of points makes it more readable, not less.
Also I feel like my
Without further ado, here is the code:
The concept is simple enough,
n equal items x in a row will be replaced by (n, x), decompressing is just the reverse.For example:
> runLengthCompress "foooo barrr"
[(1,'f'),(4,'o'),(1,' '),(1,'b'),(1,'a'),(3,'r')]As you can see the four consecutive
o have been substituted by (4,'o')About the code itself I fear I have written too little points (arguments) to my functions, hindering readability but I am not sure, maybe the lack of points makes it more readable, not less.
Also I feel like my
areInverses function is already built-in into Haskell and that I am rebuilding the wheel with it.Without further ado, here is the code:
import Data.List
import Control.Monad
import Control.Arrow
runLengthExpand :: [(Int, a)] -> [a]
runLengthExpand = concat . map (uncurry replicate)
runLengthCompress :: Eq a => [a] -> [(Int, a)]
runLengthCompress = (map (length &&& head)) . group
areInverses :: Eq b => (a -> b) -> (b -> a) -> [b] -> Bool
areInverses f g = all ((==) =<< f . g)
examples :: [[Int]]
examples = [ [3, 3, 3, 5, 5, 7, 1], [1,1,1,0,0,0,5] ]
main :: IO()
main = do
print $ runLengthCompress "foooo barrr"
print $ areInverses runLengthExpand runLengthCompress examplesSolution
You want to import only the functions you're actually going to need:
As Gurkenglas already said, use
Your
Now,
About the code itself I fear I have written too little points (arguments) to my functions, hindering readability but I am not sure, maybe the lack of points makes it more readable, not less.
Pointfree style isn't necessarily easier to read:
5 Problems with pointfree
Point-free style can (clearly) lead to Obfuscation when used unwisely.
We can split its functionality in multiple functions:
This removes the need for
However, that only checks whether
You can use QuickCheck to generate appropriate strings and lists of pairs, although you need to generate the latter by hand.
import Data.List (group)
import Control.Arrow ((&&&))As Gurkenglas already said, use
concatMap instead of concat . map. This leads torunLengthExpand :: [(Int, a)] -> [a]
runLengthExpand = concatMap (uncurry replicate)Your
runLengthCompress is fine, although (&&&) might not be known to newcomers.Now,
areInverses is too obfuscated:About the code itself I fear I have written too little points (arguments) to my functions, hindering readability but I am not sure, maybe the lack of points makes it more readable, not less.
Pointfree style isn't necessarily easier to read:
5 Problems with pointfree
Point-free style can (clearly) lead to Obfuscation when used unwisely.
We can split its functionality in multiple functions:
isInverseOn :: Eq a => (a -> b) -> (b -> a) -> a -> Bool
isInverseOn f g x = x == g (f x)
areInverses :: Eq a => (a -> b) -> (b -> a) -> [a] -> Bool
areInverses f g = all (isInverseOn f g)This removes the need for
=<< completely and is easier to read than your previous (==) =<< f . g.However, that only checks whether
g is an inverse of f, not whether f is the inverse of g. For example, g's codomain might not be the completely covered by f's domain. So a proper areInverses should also check isInverseOn g f for some appropriate values.You can use QuickCheck to generate appropriate strings and lists of pairs, although you need to generate the latter by hand.
Code Snippets
import Data.List (group)
import Control.Arrow ((&&&))runLengthExpand :: [(Int, a)] -> [a]
runLengthExpand = concatMap (uncurry replicate)isInverseOn :: Eq a => (a -> b) -> (b -> a) -> a -> Bool
isInverseOn f g x = x == g (f x)
areInverses :: Eq a => (a -> b) -> (b -> a) -> [a] -> Bool
areInverses f g = all (isInverseOn f g)Context
StackExchange Code Review Q#109684, answer score: 3
Revisions (0)
No revisions yet.