Run-length encoding in Haskell I wrote a short Haskell script to compress and decompress via the use of run length encoding.

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:

&gt; 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)] -&gt; [a]
runLengthExpand = concat . map (uncurry replicate)

runLengthCompress :: Eq a =&gt; [a] -&gt; [(Int, a)]
runLengthCompress = (map (length &amp;&amp;&amp; head)) . group

areInverses :: Eq b =&gt; (a -&gt; b) -&gt; (b -&gt; a) -&gt; [b] -&gt; Bool
areInverses f g = all ((==) =&lt;&lt; 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 examples
You want to import only the functions you're actually going to need:
import Data.List     (group)
import Control.Arrow ((&amp;&amp;&amp;))

As Gurkenglas already said, use concatMap instead of concat . map. This leads to
runLengthExpand :: [(Int, a)] -&gt; [a]
runLengthExpand = concatMap (uncurry replicate)

Your runLengthCompress is fine, although (&amp;&amp;&amp;) 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 =&gt; (a -&gt; b) -&gt; (b -&gt; a) -&gt; a -&gt; Bool
isInverseOn f g x = x == g (f x)

areInverses :: Eq a =&gt; (a -&gt; b) -&gt; (b -&gt; a) -&gt; [a] -&gt; Bool
areInverses f g = all (isInverseOn f g)

This removes the need for =&lt;&lt; completely and is easier to read than your previous (==) =&lt;&lt; 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.