Let me provide some other examples then. Often the most relatable examples in this field involve manipulating data structures, or hiding abstractions.
Sometimes you just want to reuse an existing function with 2 arguments. You name it either because you want to give it an explicit type (in many cases the exact same code can do different things depending on the type it expects). People's first exposure to point free style is often "flip", a higher-order function that takes a diadic function and swaps the order of arguments.
As an example, the "cons" function from data.text takes a character and a text object and prepends the character into the text object. It has type: Char -> Text -> Text
But what if we'd like to do this repeatedly? Ideally we'd reuse a function like foldl (reduce in javascript parlance). What we'd like is to have a function like conss that has type Text -> [Char] -> Text. Sadly, foldl expects its reducer function to take something more like Text -> Char -> Text, which is really close to what we already have with cons.
A point free solution feels pretty natural here:
conss :: Text -> [Char] -> -> Text
conss = foldl (flip cons)
We might say, "I actually want to prepend the same prefix to hundreds of strings." A simple point free way to think about reusing our old code:
prepend :: [Char] -> Text -> Text
prepend = flip conss
Often times we use point-free style when we're building other structures. Some time ago I wrote a text adventure game engine to explain Haskell to some kids, and it has this line (
https://github.com/KirinDave/Rag/blob/master/src/Rag/Parser....):
buildMaze :: [(Int, Room)] -> MazeDefinition
buildMaze = foldr (uncurry Map.insert) Map.empty
Again, a point free version of this is much more readable and direct than if I were to pattern match into the arguments. That would require a binding both on the outside for the array and in the inner reducer function, adding tons of noise:
buildMaze :: [(Int, Room)] -> MazeDefinition
buildMaze definitions = foldr reducer Map.empty definitions
where reducer = \(m, (i,r)) -> Map.insert i r m
Sometimes, point-free style can also help with very abstract code. A common way to define the functor instance for the Free monad, for example, is reasonable to follow in point free notation but pretty brutal without it:
instance Functor f => Monad (Free f) where
return = pure
Pure a >>= f = f a
Free x >>= f = Free ((>>= f) <$> x)
Trust me, you don't want to see the lambda-ized version of that inner bind. It's really, really bad. It also loses the clarity this one offers about the fact that at the end of the day, you make a big chain of functions and then fmap it (which is actually pointing to a massive performance flaw with this implementation free monad!).
I agree that the author didn't really make their point here. What's more, using the language they did will always make point free notation look awkward. Point free notation thrives in environments where partial application is automatic.