Skip to content

Haskell Recursion Guide — Recursive Functions, Tail Recursion, and Patterns

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about Haskell Recursion Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Haskell recursion replaces loops with functions that call themselves, using pattern matching on base cases and recursive cases -- with tail recursion and accumulators enabling efficient computation that compiles to tight loops.

Basic Recursion

-- Factorial
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)

-- List sum
sumList :: [Integer] -> Integer
sumList []     = 0
sumList (x:xs) = x + sumList xs

-- Length
length' :: [a] -> Integer
length' []     = 0
length' (_:xs) = 1 + length' xs

Tail Recursion

-- Tail recursive factorial (accumulator)
factorial' :: Integer -> Integer -> Integer
factorial' 0 acc = acc
factorial' n acc = factorial' (n - 1) (n * acc)

factorial n = factorial' n 1

-- Tail recursive reverse
reverse' :: [a] -> [a]
reverse' list = go list []
  where
    go []     acc = acc
    go (x:xs) acc = go xs (x:acc)

Multiple Recursion

-- Fibonacci (naive, exponential)
fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

-- Fibonacci (efficient, linear)
fib' n = go n 0 1
  where
    go 0 a _ = a
    go n a b = go (n - 1) b (a + b)

Recursion on Trees

data Tree a = Empty | Node a (Tree a) (Tree a)

treeDepth :: Tree a -> Integer
treeDepth Empty        = 0
treeDepth (Node _ l r) = 1 + max (treeDepth l) (treeDepth r)

treeSum :: Num a => Tree a -> a
treeSum Empty         = 0
treeSum (Node v l r)  = v + treeSum l + treeSum r

Common Mistakes

1. Missing base case

Every recursive function needs at least one base case. Without it, the recursion never terminates.

2. Non-tail recursion on large input

sumList [1..1000000] overflows the stack. Use tail recursion with an accumulator or folds.

3. Naive Fibonacci

The naive fib 40 has exponential complexity. Use tail recursion or memoization for large values.

Practice Questions

1. What is the base case in recursion? The smallest input that returns a direct answer without recursing. Often empty list, 0, or null constructor.

2. What is tail recursion? The recursive call is the last operation in the function. GHC can optimize this to a loop (no stack growth).

3. Why is naive Fibonacci slow? Each call creates two recursive calls, leading to O(2^n) complexity. Tail-recursive version is O(n).

FAQ

{{< faq question="Does GHC optimize all tail calls?" >}} GHC performs tail-call optimization (TCO) for self-recursive tail calls. Mutual tail recursion may not always be optimized. {{< /faq >}}

{{< faq question="What is an accumulator?" >}} An extra parameter that accumulates intermediate results, passed through recursive calls to build the final answer. {{< /faq >}}

{{< faq question="Can I have mutual recursion?" >}} Yes. Functions calling each other: even 0 = True; even n = odd (n-1); odd 0 = False; odd n = even (n-1). {{< /faq >}}

What's Next

Now learn about higher-order functions.

Topic Description Link
Higher-Order Functions Functions as arguments and results {{< ref "08-higher-order-functions" >}}
Functors Mapping over contexts {{< ref "09-functors" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro