Haskell - Complete Beginner’s Guide
What is Haskell? Haskell is a purely functional programming language. If you want to understand what functional programming really means, Haskell is it! Pure, elegant, and mathematically beautiful. Perfect for building reliable systems!
1. Getting Started
Your First Program
main = putStrLn "Hello, Haskell!"
-- This prints: Hello, Haskell!Comments
-- Single line comment
{- Multi-line
comment
like this -}2. Basic Types and Functions
Simple Expressions
ghci> 5 + 3
8
ghci> 10 - 4
6
ghci> 3 * 4
12
ghci> 15 / 3
5.0
ghci> 17 `mod` 5
2
ghci> 2 ^ 3
8Declaring Variables and Functions
-- Variable (in GHCi)
let x = 5
let name = "Alice"
-- Function definition
add a b = a + b
-- Call function
add 5 3 -- Returns 8
-- Function with pattern matching
greet "Alice" = "Hello, Alice!"
greet name = "Hello, " ++ name ++ "!"
greet "Alice" -- "Hello, Alice!"
greet "Bob" -- "Hello, Bob!"3. Type Annotations
Declaring Types
-- Function with type annotation
add :: Int -> Int -> Int
add a b = a + b
-- Variables with type
x :: Int
x = 5
y :: String
y = "Hello"
z :: Double
z = 3.14
-- Lists
nums :: [Int]
nums = [1, 2, 3, 4, 5]
-- Boolean
active :: Bool
active = TrueCommon Types
Int -- Integers: 42, -10
Integer -- Big integers
Double -- Decimals: 3.14
Float -- Single precision
String -- Text: "Hello"
Char -- Single character: 'a'
Bool -- True or False
[Int] -- List of integers
[String] -- List of strings
(Int, String) -- Tuple: (1, "hello")4. Strings and Lists
Strings
-- String is a list of characters
"Hello"
-- Concatenation
"Hello" ++ " " ++ "World" -- "Hello World"
-- String length
length "Hello" -- 5
-- Get character at position
"Hello" !! 0 -- 'H'
-- Useful functions
head "Hello" -- 'H'
tail "Hello" -- "ello"
init "Hello" -- "Hell"
last "Hello" -- 'o'
reverse "Hello" -- "olleH"Lists
-- Create lists
[1, 2, 3, 4, 5]
['a', 'b', 'c']
-- Ranges
[1..5] -- [1,2,3,4,5]
[1, 3..10] -- [1,3,5,7,9]
[10, 9..1] -- [10,9,8,7,6,5,4,3,2,1] (descending)
replicate 3 5 -- [5,5,5]
-- List operations
[1,2,3] ++ [4,5] -- [1,2,3,4,5] (concatenate)
5 : [1,2,3] -- [5,1,2,3] (cons - prepend)
head [1,2,3] -- 1
tail [1,2,3] -- [2,3]
length [1,2,3] -- 3
sum [1,2,3,4,5] -- 15
product [1,2,3,4] -- 24
reverse [1,2,3] -- [3,2,1]5. Lists and Comprehensions
List Comprehensions (Beautiful!)
-- List all numbers 1-10 squared
[x^2 | x <- [1..10]]
-- [1,4,9,16,25,36,49,64,81,100]
-- Only even numbers squared
[x^2 | x <- [1..10], even x]
-- [4,16,36,64,100]
-- Pairs of numbers
[(x, y) | x <- [1,2,3], y <- [4,5,6]]
-- [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),...]
-- With multiple conditions
[x | x <- [1..20], x > 10, x < 15]
-- [11,12,13,14]Useful List Functions
-- Map (transform each)
map (\x -> x * 2) [1,2,3,4] -- [2,4,6,8]
map (+1) [1,2,3] -- [2,3,4]
-- Filter (keep matching)
filter even [1,2,3,4,5,6] -- [2,4,6]
filter (>3) [1,2,3,4,5] -- [4,5]
-- Fold (combine all)
foldl (+) 0 [1,2,3,4,5] -- 15 (sum)
foldl (*) 1 [1,2,3,4] -- 24 (product)
-- Zip (pair up elements)
zip [1,2,3] ['a','b','c'] -- [(1,'a'),(2,'b'),(3,'c')]6. Functions and Pattern Matching
Pattern Matching
-- Matching specific values
greet :: String -> String
greet "Alice" = "Hello, Alice!"
greet "Bob" = "Hi, Bob!"
greet name = "Hello, " ++ name
-- Matching patterns
isEmpty :: [a] -> Bool
isEmpty [] = True -- Empty list
isEmpty _ = False -- Anything else
-- Matching list structure
getFirst :: [a] -> a
getFirst (x:_) = x -- First element
getSecond :: [a] -> a
getSecond (_:x:_) = x -- Second element
-- Recursive patterns
sumList :: [Int] -> Int
sumList [] = 0 -- Base case
sumList (x:xs) = x + sumList xs -- Recursive caseGuards
-- Use guards for conditions
classify :: Int -> String
classify x
| x < 0 = "Negative"
| x == 0 = "Zero"
| x < 10 = "Single digit"
| otherwise = "Multiple digits"7. Recursion (Fundamental!)
Classic Recursion Examples
-- Factorial
factorial :: Int -> Int
factorial 0 = 1 -- Base case
factorial n = n * factorial (n-1) -- Recursive case
factorial 5 -- 120
-- List length
listLength :: [a] -> Int
listLength [] = 0
listLength (_:xs) = 1 + listLength xs
listLength [1,2,3] -- 3
-- List reversal
reverseList :: [a] -> [a]
reverseList [] = []
reverseList (x:xs) = reverseList xs ++ [x]
-- Get max element
maxElement :: [Int] -> Int
maxElement [x] = x
maxElement (x:xs) = max x (maxElement xs)8. Higher-Order Functions
Functions That Work with Functions
-- Apply function twice
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
applyTwice (+1) 5 -- 7
-- Function composition
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
let double = (*2)
let addOne = (+1)
(double . addOne) 5 -- 12: (5+1)*2
-- Map and filter (already shown but powerful!)
map (+1) [1,2,3] -- [2,3,4]
filter (>2) [1,2,3,4] -- [3,4]9. Tuples
Working with Tuples
-- Create tuple
let person = ("John", 30, "NYC")
-- Access elements
fst ("a", "b") -- "a"
snd ("a", "b") -- "b"
-- Pattern match
let (name, age, city) = person
-- name = "John", age = 30, city = "NYC"
-- List of tuples
let users = [("Alice", 25), ("Bob", 30), ("Charlie", 22)]
-- Get all names
map fst users -- ["Alice","Bob","Charlie"]10. Maybe Type (Null Safety!)
Handling Missing Values
-- Maybe is Some(value) or Nothing
findUser :: Int -> Maybe String
findUser 1 = Just "Alice"
findUser 2 = Just "Bob"
findUser _ = Nothing
-- Pattern match on Maybe
case findUser 1 of
Just name -> "Found: " ++ name
Nothing -> "Not found"
-- Safer operations
findUser 1 >>= \user -> Just (user ++ "!") -- Just "Alice!"
findUser 3 >>= \user -> Just (user ++ "!") -- Nothing11. Practical Example
Count Word Occurrences
import Data.List (group, sort)
countWords :: String -> [(String, Int)]
countWords sentence =
let words = words sentence
sorted = sort words
grouped = group sorted
in map (\g -> (head g, length g)) grouped
-- Usage:
-- countWords "hello world hello haskell hello"
-- [("hello",3),("haskell",1),("world",1)]Fibonacci Sequence
-- Infinite list of Fibonacci numbers
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
-- Get first n Fibonacci numbers
take 10 fibs -- [0,1,1,2,3,5,8,13,21,34]12. Key Concepts
Immutability
-- Everything is immutable
let x = 5
-- x = 10 -- Can't do this in Haskell!
let y = 10 -- Must create new variable
-- But lists can be efficiently transformed
let nums = [1,2,3]
let doubled = map (*2) nums -- [2,4,6]Lazy Evaluation
-- Haskell only computes what it needs
let infiniteList = [1..] -- Infinite list!
take 5 infiniteList -- [1,2,3,4,5] (only computes first 5)
-- This doesn't compute forever
filter (<5) [1..] -- [1,2,3,4] (stops at 5)