Why Haskell? A Gentle Introduction to Functional Programming
Table of Contents
An accessible introduction to Haskell — the purely functional programming language that makes math nerds blush with joy. Covers pure functions, lazy evaluation, type systems, monads, and real-world applications. Haskell is the Chuck Norris of programming languages -- strong, robust, and utterly committed to immutability. It is a purely functional language with a tight type system and lazy evaluation strategy that lets you tackle infinite data structures without breaking a sweat. If you have ever looked at a sorting algorithm and thought "this could be more mathematical", Haskell was made for you. Haskell is a statically typed, purely functional programming language with roots in academic research from the 1980s. A committee led by researchers inspired by Haskell Curry (yes, the language is named after him) set out to build a language grounded in mathematical elegance and correctness. Today it is used everywhere from financial systems and compilers to security research and web backends. Its influence is visible in features that have since been adopted by Rust, Scala, Swift, and even Python. In Haskell, functions have no side effects by default. Given the same input, a function always returns the same output. This property -- called referential transparency -- makes code dramatically easier to reason about, test, and parallelise. Compare that quicksort to an imperative implementation. Same algorithm, a fraction of the code. Haskell promotes a declarative style -- you describe what you want, not how to compute it. This leads to code that reads almost like mathematics. Function composition with Haskell's type system catches bugs at compile time that would only surface at runtime in dynamic languages. It is not just type checking -- it is type-directed development. The Haskell uses lazy evaluation -- values are only computed when they are actually needed. This is what allows Haskell to work with infinite data structures without running out of memory. Laziness also enables efficient I/O streaming -- large files are read on demand rather than loaded entirely into memory. Monads are one of Haskell's most famous (and most misunderstood) features. At their core, they are a pattern for chaining computations that may have effects -- like failure, state, or I/O. If any step returns Type classes define behaviour that different types can implement -- similar to interfaces in other languages, but more powerful. Haskell lets you model your domain precisely using sum types and product types. The compiler enforces exhaustive pattern matching -- if you add a new shape, every function that handles shapes will warn you at compile time. The Haskell ecosystem is mature and well-tooled. Build tools: Cabal and Stack manage dependencies and ensure reproducible builds. Package repositories: Hackage hosts over 16,000 packages. Stackage provides curated stable snapshots. Editor support: HLS (Haskell Language Server) gives you completions, type hints, and inline errors in VS Code, Neovim, Emacs, and more. Haskell is not just an academic language -- it powers production systems. Facebook uses Haskell internally for spam filtering. Standard Chartered uses it for financial modelling. IOHK built the entire Cardano blockchain in Haskell specifically for its correctness guarantees. The Haskell community is welcoming and genuinely enthusiastic about the language. Good starting points: The community values correctness, thoughtful design, and good documentation. Questions at any level are welcome. Install GHC and Cabal via GHCup -- the recommended toolchain manager: Then start a REPL: Haskell rewards patience. The first week is confusing. The second week, things click. By the third week you will find yourself annoyed at every other language for not having algebraic data types. Happy Haskelling.![]()
What is Haskell?
1. Pure Functional
-- Fibonacci sequence
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)-- Quicksort in 3 lines
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = quicksort [y | y <- xs, y <= x]
++ [x]
++ quicksort [y | y <- xs, y > x] 2. Expressive and Concise Syntax
-- List comprehension: squares of 1 to 10
squares :: [Int]
squares = [x * x | x <- [1..10]]-- Function composition with (.)
-- Total length of all strings in a list
totalLength :: [String] -> Int
totalLength = sum . map length. is one of Haskell's most powerful features. You build complex transformations by chaining simple functions together -- no intermediate variables, no mutation. 3. Powerful Type System
-- Safe head: no more runtime crashes on empty lists
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x-- Polymorphic addition: works on Int, Float, Double...
add :: Num a => a -> a -> a
add x y = x + yMaybe type is Haskell's answer to null pointer exceptions. Instead of crashing, you get Nothing -- a value you are forced to handle explicitly. This single idea has inspired Option in Rust and Swift, and Optional in Java. 4. Laziness and Efficiency
-- Infinite Fibonacci sequence
-- Only computes as many values as you ask for
fibonacci :: [Integer]
fibonacci = 0 : 1 : zipWith (+) fibonacci (tail fibonacci)
-- Take the first 10
first10 :: [Integer]
first10 = take 10 fibonacci
-- [0,1,1,2,3,5,8,13,21,34]-- Infinite list of primes using Sieve of Eratosthenes
primes :: [Integer]
primes = sieve [2..]
where
sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
-- First 5 primes
first5primes :: [Integer]
first5primes = take 5 primes
-- [2,3,5,7,11] 5. High-Level Abstractions
Monads
-- Safe division using the Maybe monad
safeDivide :: Int -> Int -> Maybe Int
safeDivide _ 0 = Nothing
safeDivide x y = Just (x `div` y)
-- Chain two divisions safely
example :: Int -> Int -> Maybe Int
example x y = do
q <- safeDivide x y
result <- safeDivide (q + 2) 5
return (result * 10)Nothing, the whole chain short-circuits. No if-else chains, no null checks -- just clean sequential logic. Type Classes
-- Custom equality for a Person type
data Person = Person { name :: String, age :: Int }
instance Eq Person where
(Person n1 a1) == (Person n2 a2) = n1 == n2 && a1 == a2
person1 :: Person
person1 = Person "Alice" 25
person2 :: Person
person2 = Person "Bob" 30
-- False
example :: Bool
example = person1 == person2 Algebraic Data Types
-- A shape is either a Circle or a Rectangle -- nothing else
data Shape = Circle Double | Rectangle Double Double
area :: Shape -> Double
area (Circle r) = pi * r * r
area (Rectangle w h) = w * h
example :: Double
example = area (Circle 5.0)
-- 78.53... 6. Ecosystem and Tooling
Library Purpose aesonJSON parsing and encoding servantType-safe web API development conduitStreaming data processing lensFunctional data manipulation parsec / attoparsecParser combinators QuickCheckProperty-based testing STMSoftware Transactional Memory persistentDatabase persistence warpHigh-performance web server hmatrixLinear algebra 7. Real-World Applications
Project What it is GHC The Glasgow Haskell Compiler -- written in Haskell Pandoc Universal document converter ShellCheck Shell script linter used by millions XMonad Tiling window manager Cardano Proof-of-stake blockchain Hledger Plain-text accounting software GitAnnex Distributed file management HLS Haskell Language Server 8. Community and Support
Getting Started
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | shghci-- Try it immediately
Prelude> map (*2) [1..10]
[2,4,6,8,10,12,14,16,18,20]
Prelude> filter even [1..20]
[2,4,6,8,10,12,14,16,18,20] Resources