Avatar of genos
0
1
Genius
0
0

genos's solution

to Run Length Encoding in the Haskell Track

Instructions
Test suite
Solution

Implement run-length encoding and decoding.

Run-length encoding (RLE) is a simple form of data compression, where runs (consecutive data elements) are replaced by just one data value and count.

For example we can represent the original 53 characters with only 13.

"WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB"  ->  "12WB12W3B24WB"

RLE allows the original data to be perfectly reconstructed from the compressed data, which makes it a lossless data compression.

"AABCCCDEEEE"  ->  "2AB3CD4E"  ->  "AABCCCDEEEE"

For simplicity, you can assume that the unencoded string will only contain the letters A through Z (either lower or upper case) and whitespace. This way data to be encoded will never contain any numbers and numbers inside data to be decoded always represent the count for the following character.

Getting Started

For installation and learning resources, refer to the exercism help page.

Running the tests

To run the test suite, execute the following command:

stack test

If you get an error message like this...

No .cabal file found in directory

You are probably running an old stack version and need to upgrade it.

Otherwise, if you get an error message like this...

No compiler found, expected minor version match with...
Try running "stack setup" to install the correct GHC...

Just do as it says and it will download and install the correct compiler version:

stack setup

Running GHCi

If you want to play with your solution in GHCi, just run the command:

stack ghci

Feedback, Issues, Pull Requests

The exercism/haskell repository on GitHub is the home for all of the Haskell exercises.

If you have feedback about an exercise, or want to help implementing a new one, head over there and create an issue. We'll do our best to help you!

Source

Wikipedia https://en.wikipedia.org/wiki/Run-length_encoding

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

Tests.hs

{-# LANGUAGE RecordWildCards #-}

import Data.Foldable     (for_)
import Test.Hspec        (Spec, describe, it, shouldBe)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)

import RunLength (encode, decode)

main :: IO ()
main = hspecWith defaultConfig {configFastFail = True} specs

specs :: Spec
specs = do
          describe "decode" $ for_ decodeCases $ test decode
          describe "encode" $ for_ encodeCases $ test encode
          describe "both"   $ for_ bothCases   $ test (decode . encode)
  where
    test f Case{..} = it description $ f input `shouldBe` expected

data Case = Case { description :: String
                 , input       :: String
                 , expected    :: String
                 }

encodeCases :: [Case]
encodeCases =
    [ Case { description = "encode empty string"
           , input       = ""
           , expected    = ""
           }
    , Case { description = "encode single characters only"
           , input       = "XYZ"
           , expected    = "XYZ"
           }
    , Case { description = "encode simple"
           , input       = "AABBBCCCC"
           , expected    = "2A3B4C"
           }
    , Case { description = "encode with single values"
           , input       = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB"
           , expected    = "12WB12W3B24WB"
           }
    , Case { description = "encode whitespace"
           , input       = "  hsqq qww  "
           , expected    = "2 hs2q q2w2 "
           }
    , Case { description = "encode lowercase"
           , input       = "aabbbcccc"
           , expected    = "2a3b4c"
           }
    ]

decodeCases :: [Case]
decodeCases =
    [ Case { description = "decode empty string"
           , input       = ""
           , expected    = ""
           }
    , Case { description = "decode single characters only"
           , input       = "XYZ"
           , expected    = "XYZ"
           }
    , Case { description = "decode simple"
           , input       = "2A3B4C"
           , expected    = "AABBBCCCC"
           }
    , Case { description = "decode with single values"
           , input       = "12WB12W3B24WB"
           , expected    = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB"
           }
    , Case { description = "decode whitespace"
           , input       = "2 hs2q q2w2 "
           , expected    = "  hsqq qww  "
           }
    , Case { description = "decode lowercase"
           , input       = "2a3b4c"
           , expected    = "aabbbcccc"
           }
    ]

bothCases :: [Case]
bothCases =
    [ Case { description = "decode . encode combination"
           , input       = "zzz ZZ  zZ"
           , expected    = "zzz ZZ  zZ"
           }
    ]
module RunLength (decode, encode) where

import Control.Arrow ((&&&))
import Data.Char     (isDigit)
import Data.List     (group)

encode :: String -> String
encode =
  concatMap (uncurry (++)) . fmap (show' . length &&& (:[]) . head) . group
  where show' n = if n == 1 then "" else show n

decode :: String -> String
decode [] = []
decode s  = replicate (read' i) (head s') ++ decode (tail s')
 where
  (i, s') = span isDigit s
  read' i = if i == "" then 1 else read i

What can you learn from this solution?

A huge amount can be learnt from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that I could read more about to develop my understanding?