Haskell
Programming
Code Optimization
Functional Programming
Code Conciseness

How make this piece of Haskell code more concise?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Haskell's design encourages concise, expressive code through features like higher-order functions, function composition, point-free style, pattern matching, and list comprehensions. Understanding these techniques lets you transform verbose Haskell into compact, idiomatic expressions without sacrificing readability.

Example: Sum of Squares of Even Numbers

Verbose Version

haskell
1sumOfSquaresOfEvens :: [Int] -> Int
2sumOfSquaresOfEvens xs =
3  let evens = filter isEven xs
4      squares = map square evens
5  in sum squares
6  where
7    isEven x = x `mod` 2 == 0
8    square x = x * x

Concise Version

haskell
sumOfSquaresOfEvens :: [Int] -> Int
sumOfSquaresOfEvens = sum . map (^2) . filter even

This uses function composition (.), the built-in even, and sections ((^2)).

Technique 1: Function Composition

The . operator chains functions right to left:

haskell
1-- Verbose
2f x = h (g (k x))
3
4-- Concise
5f = h . g . k
6
7-- Example: get uppercase first letter of a string
8firstUpperChar :: String -> Char
9firstUpperChar = toUpper . head
10
11-- Pipeline: words -> count -> show
12wordCountStr :: String -> String
13wordCountStr = show . length . words

Technique 2: Point-Free Style

Remove the explicit argument when it appears at the end:

haskell
1-- With explicit argument (pointful)
2double x = x * 2
3addOne x = x + 1
4isPositive x = x > 0
5
6-- Point-free
7double = (* 2)
8addOne = (+ 1)
9isPositive = (> 0)
10
11-- More complex example
12-- Pointful
13process xs = sort (nub (filter (> 0) xs))
14
15-- Point-free
16process = sort . nub . filter (> 0)

Technique 3: Using Sections

Sections partially apply operators:

haskell
1-- Sections for common operations
2map (* 2) [1, 2, 3]       -- [2, 4, 6]
3filter (> 3) [1, 2, 3, 4, 5]  -- [4, 5]
4map (++ "!") ["hi", "bye"]    -- ["hi!", "bye!"]
5
6-- Verbose
7squareAll xs = map (\x -> x * x) xs
8
9-- Concise
10squareAll = map (^2)

Technique 4: List Comprehensions

haskell
1-- Verbose
2evenSquares :: [Int] -> [Int]
3evenSquares xs = map (\x -> x * x) (filter even xs)
4
5-- List comprehension
6evenSquares xs = [x * x | x <- xs, even x]
7
8-- Pythagorean triples
9triples n = [(a,b,c) | c <- [1..n], b <- [1..c], a <- [1..b],
10                        a*a + b*b == c*c]

Technique 5: Pattern Matching

haskell
1-- Verbose with if-else
2describeList :: [a] -> String
3describeList xs =
4  if null xs
5    then "empty"
6    else if length xs == 1
7      then "singleton"
8      else "longer"
9
10-- Pattern matching
11describeList :: [a] -> String
12describeList []  = "empty"
13describeList [_] = "singleton"
14describeList _   = "longer"

Technique 6: Guards

haskell
1-- Verbose if-else chain
2bmi :: Double -> String
3bmi x = if x < 18.5
4        then "underweight"
5        else if x < 25.0
6          then "normal"
7          else if x < 30.0
8            then "overweight"
9            else "obese"
10
11-- Guards
12bmi :: Double -> String
13bmi x
14| x < 18.5  = "underweight" | x < 25.0  = "normal" | x < 30.0  = "overweight" | otherwise  = "obese" ``` ## Technique 7: Higher-Order Functions Replace explicit recursion with standard library functions: ```haskell -- Explicit recursion sumList :: [Int] -> Int sumList []     = 0 sumList (x:xs) = x + sumList xs -- Using fold sumList :: [Int] -> Int sumList = foldl' (+) 0 -- More examples product' = foldl' (*) 1 maximum' = foldl1 max concat'  = foldl' (++) [] any'     = foldl' (\acc x -> acc |  |
15| --- | --- | --- | --- | --- |
16| `\x -> x + 1` | `(+ 1)` |
17| `\x -> f (g x)` | `f . g` |
18| `map (\x -> x * x) xs` | `map (^2) xs` |
19| `filter (\x -> x > 0) xs` | `filter (> 0) xs` |
20| `foldl (\acc x -> acc + x) 0` | `foldl (+) 0` |
21| `if x then True else False` | `x` |
22| `\x -> not (null x)` | `not . null` |
23
24## Common Pitfalls
25
26* **Over-abstracting**: Point-free style becomes unreadable with complex functions. `f = g . h . k . m . n` is hard to follow. Add type signatures and use pointful style when clarity demands it.
27* **Space leaks with foldl**: Use `foldl'` (strict) from `Data.List` instead of `foldl` (lazy) to avoid stack overflow on large lists.
28* **Operator precedence**: Function composition `.` and application `$` have different precedences. `f . g $ x` means `(f . g) x`, not `f . (g $ x)`.
29* **Readability**: Concise code is not always better. Choose readability over cleverness, especially in team environments.
30* **Type inference**: Overly point-free code can confuse GHC's type inference. Add explicit type signatures to help the compiler and future readers.
31
32## Summary
33
34* Use `.` for function composition to chain transformations
35* Use sections like `(+1)`, `(>0)`, `(^2)` for partial operator application
36* Use point-free style when it improves clarity: `f = sum . map (^2) . filter even`
37* Replace explicit recursion with `map`, `filter`, `foldl'`, and list comprehensions
38* Balance conciseness with readabilityadd type signatures and avoid overly abstract code

Course illustration
Course illustration

All Rights Reserved.