Haskell
Programming Language
Haskell
Overview
Haskell is a pure functional programming language characterized by a powerful type system, lazy evaluation, and mathematical elegance, serving both academic and practical purposes.
Details
Haskell is a pure functional programming language standardized by an academic committee in 1990, named after mathematician Haskell Curry. It adopts a pure functional paradigm where all computations are expressed as mathematical functions, and side effects are explicitly managed through the type system. It provides advanced features such as lazy evaluation (computation on demand), a powerful static type system, type inference, higher-order functions, pattern matching, algebraic data types, and monads. It is utilized in fields such as academic research, programming language theory, compiler design, cryptography, and financial systems, playing an important role in spreading functional programming concepts to other languages.
Code Examples
Hello World
-- Basic output
main :: IO ()
main = putStrLn "Hello, World!"
-- Multiple line output
main2 :: IO ()
main2 = do
putStrLn "Hello, Haskell!"
putStrLn "Pure functional programming language"
putStrLn "Features lazy evaluation and powerful type system"
-- Output using variables
greetingProgram :: IO ()
greetingProgram = do
let name = "John"
age = 25
putStrLn $ "My name is " ++ name ++ " and I am " ++ show age ++ " years old."
-- String interpolation style
formatGreeting :: String -> Int -> String
formatGreeting name age = "Name: " ++ name ++ ", Age: " ++ show age
main3 :: IO ()
main3 = putStrLn $ formatGreeting "Alice" 30
Data Types and Variables
-- Basic data types
number :: Int
number = 42
bigNumber :: Integer -- Arbitrary precision integer
bigNumber = 12345678901234567890
floatValue :: Float
floatValue = 3.14
doubleValue :: Double
doubleValue = 3.141592653589793
character :: Char
character = 'A'
text :: String
text = "string" -- String is an alias for [Char]
boolean :: Bool
boolean = True
-- Lists
numberList :: [Int]
numberList = [1, 2, 3, 4, 5]
stringList :: [String]
stringList = ["apple", "banana", "cherry"]
-- Infinite lists (due to lazy evaluation)
infiniteNumbers :: [Int]
infiniteNumbers = [1..]
-- List ranges
rangeList :: [Int]
rangeList = [1..10]
evenNumbers :: [Int]
evenNumbers = [2, 4..20]
-- Tuples
coordinate :: (Int, Int)
coordinate = (10, 20)
person :: (String, Int, Bool)
person = ("John Doe", 30, True)
-- Maybe type (null safety)
maybeName :: Maybe String
maybeName = Just "Alice"
noName :: Maybe String
noName = Nothing
-- Either type (error handling)
result :: Either String Int
result = Right 42
errorResult :: Either String Int
errorResult = Left "An error occurred"
-- Custom data types
data Color = Red | Green | Blue | RGB Int Int Int
deriving (Show, Eq)
data Person = Person
{ personName :: String
, personAge :: Int
, personEmail :: String
} deriving (Show)
-- Usage examples
redColor :: Color
redColor = Red
customColor :: Color
customColor = RGB 255 128 0
john :: Person
john = Person "John Doe" 25 "[email protected]"
-- Type classes (interfaces)
class Describable a where
describe :: a -> String
instance Describable Color where
describe Red = "Red color"
describe Green = "Green color"
describe Blue = "Blue color"
describe (RGB r g b) = "RGB(" ++ show r ++ "," ++ show g ++ "," ++ show b ++ ")"
Function Definition and Pattern Matching
-- Basic function definition
add :: Int -> Int -> Int
add x y = x + y
-- Curried function
addCurried :: Int -> (Int -> Int)
addCurried x = \y -> x + y
-- Pattern matching
factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)
-- Guards (conditional branches)
classifyNumber :: Int -> String
classifyNumber n
| n < 0 = "Negative number"
| n == 0 = "Zero"
| n <= 10 = "1 to 10"
| otherwise = "Greater than 10"
-- List pattern matching
listLength :: [a] -> Int
listLength [] = 0
listLength (_:xs) = 1 + listLength xs
listHead :: [a] -> Maybe a
listHead [] = Nothing
listHead (x:_) = Just x
-- Complex pattern matching
processData :: Maybe (Either String Int) -> String
processData Nothing = "No data"
processData (Just (Left err)) = "Error: " ++ err
processData (Just (Right val)) = "Value: " ++ show val
-- Higher-order functions
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
-- Function composition
compose :: (b -> c) -> (a -> b) -> a -> c
compose f g x = f (g x)
-- Operator definition
(.:) :: (b -> c) -> (a -> b) -> a -> c
(.:) = compose
-- Anonymous functions (lambdas)
square :: Int -> Int
square = \x -> x * x
-- where clause
calculateCircle :: Double -> (Double, Double)
calculateCircle r = (circumference, area)
where
circumference = 2 * pi * r
area = pi * r * r
-- let expression
calculateRectangle :: Double -> Double -> Double
calculateRectangle width height =
let perimeter = 2 * (width + height)
area = width * height
in perimeter + area
-- Partial application
addFive :: Int -> Int
addFive = add 5
multiplyByTen :: Int -> Int
multiplyByTen = (*) 10
-- Usage examples
exampleUsage :: IO ()
exampleUsage = do
print $ add 10 20
print $ factorial 5
print $ classifyNumber 7
print $ listLength [1, 2, 3, 4]
print $ applyTwice (+1) 5
print $ addFive 15
List Processing and Higher-Order Functions
-- map function (apply function to each element)
squareList :: [Int] -> [Int]
squareList = map (^2)
-- filter function (extract elements matching condition)
evenOnly :: [Int] -> [Int]
evenOnly = filter even
-- fold function (reduce list to single value)
sumList :: [Int] -> Int
sumList = foldr (+) 0
productList :: [Int] -> Int
productList = foldr (*) 1
-- foldl (left fold)
reverseList :: [a] -> [a]
reverseList = foldl (flip (:)) []
-- List comprehensions
squares :: [Int]
squares = [x^2 | x <- [1..10]]
evenSquares :: [Int]
evenSquares = [x^2 | x <- [1..10], even x]
-- Conditional list comprehensions
pythagoreanTriples :: [(Int, Int, Int)]
pythagoreanTriples = [(a, b, c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]
-- zipWith (combine two lists)
addLists :: [Int] -> [Int] -> [Int]
addLists = zipWith (+)
-- take (get first n elements)
firstFive :: [a] -> [a]
firstFive = take 5
-- drop (remove first n elements)
skipFive :: [a] -> [a]
skipFive = drop 5
-- concat (flatten list of lists)
flattenList :: [[a]] -> [a]
flattenList = concat
-- concatMap (map then concat)
duplicateElements :: [a] -> [a]
duplicateElements = concatMap (\x -> [x, x])
-- Custom higher-order function
mapMaybe :: (a -> Maybe b) -> [a] -> [b]
mapMaybe _ [] = []
mapMaybe f (x:xs) = case f x of
Nothing -> mapMaybe f xs
Just y -> y : mapMaybe f xs
-- Infinite list processing (lazy evaluation)
fibonacci :: [Int]
fibonacci = 0 : 1 : zipWith (+) fibonacci (tail fibonacci)
primes :: [Int]
primes = sieve [2..]
where
sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
-- Usage examples
listExamples :: IO ()
listExamples = do
print $ squareList [1, 2, 3, 4, 5]
print $ evenOnly [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print $ sumList [1, 2, 3, 4, 5]
print $ take 10 squares
print $ take 10 fibonacci
print $ take 10 primes
print $ addLists [1, 2, 3] [4, 5, 6]
Monads and do-notation
-- Maybe monad
safeDivide :: Double -> Double -> Maybe Double
safeDivide _ 0 = Nothing
safeDivide x y = Just (x / y)
safeSquareRoot :: Double -> Maybe Double
safeSquareRoot x
| x < 0 = Nothing
| otherwise = Just (sqrt x)
-- Maybe monad chaining
safeCalculation :: Double -> Double -> Maybe Double
safeCalculation x y = do
result1 <- safeDivide x y
result2 <- safeSquareRoot result1
return (result2 * 2)
-- Or using bind operator
safeCalculation' :: Double -> Double -> Maybe Double
safeCalculation' x y =
safeDivide x y >>= safeSquareRoot >>= \result -> return (result * 2)
-- List monad
combinations :: [Int] -> [Int] -> [(Int, Int)]
combinations xs ys = do
x <- xs
y <- ys
guard (x + y > 5) -- Filter condition
return (x, y)
-- IO monad
getUserInput :: IO (String, Int)
getUserInput = do
putStrLn "Enter your name:"
name <- getLine
putStrLn "Enter your age:"
ageStr <- getLine
let age = read ageStr :: Int
return (name, age)
interactiveProgram :: IO ()
interactiveProgram = do
(name, age) <- getUserInput
putStrLn $ "Hello, " ++ name ++ "!"
putStrLn $ "You are " ++ show age ++ " years old."
when (age >= 20) $ putStrLn "You are an adult!"
-- Custom monad (State monad example)
newtype State s a = State { runState :: s -> (a, s) }
instance Functor (State s) where
fmap f (State g) = State $ \s -> let (a, s') = g s in (f a, s')
instance Applicative (State s) where
pure a = State $ \s -> (a, s)
(State f) <*> (State g) = State $ \s ->
let (f', s') = f s
(a, s'') = g s'
in (f' a, s'')
instance Monad (State s) where
return = pure
(State g) >>= f = State $ \s ->
let (a, s') = g s
(State h) = f a
in h s'
get :: State s s
get = State $ \s -> (s, s)
put :: s -> State s ()
put s = State $ \_ -> ((), s)
-- State monad usage example
counter :: State Int Int
counter = do
count <- get
put (count + 1)
return count
runCounter :: (Int, Int)
runCounter = runState (counter >> counter >> counter) 0
Functors and Applicatives
-- Functor type class
-- fmap :: (a -> b) -> f a -> f b
-- Maybe Functor usage examples
functorExamples :: IO ()
functorExamples = do
print $ fmap (*2) (Just 5) -- Just 10
print $ fmap (*2) Nothing -- Nothing
print $ fmap show [1, 2, 3] -- ["1", "2", "3"]
-- Custom Functor
data Box a = Box a deriving (Show)
instance Functor Box where
fmap f (Box x) = Box (f x)
-- Applicative Functor
-- pure :: a -> f a
-- (<*>) :: f (a -> b) -> f a -> f b
applicativeExamples :: IO ()
applicativeExamples = do
print $ pure (+) <*> Just 3 <*> Just 5 -- Just 8
print $ pure (+) <*> [1, 2] <*> [10, 20] -- [11, 21, 12, 22]
-- Combining multiple Maybes
combineThree :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int
combineThree mx my mz = (+) <$> mx <*> ((*) <$> my <*> mz)
-- Alternative type class
-- empty :: f a
-- (<|>) :: f a -> f a -> f a
alternativeExamples :: IO ()
alternativeExamples = do
print $ Nothing <|> Just 5 <|> Just 3 -- Just 5
print $ [] <|> [1, 2] <|> [3, 4] -- [1, 2]
-- Traversable (combining list processing with monads)
-- traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traversableExamples :: IO ()
traversableExamples = do
print $ traverse safeDivide [10, 8, 6] <*> pure 2 -- Just [5.0, 4.0, 3.0]
print $ traverse (\x -> if x > 0 then Just x else Nothing) [1, 2, -3] -- Nothing
Type-Level Programming
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
-- Type-level natural numbers
data Nat = Zero | Succ Nat
-- Length-indexed vectors
data Vec (n :: Nat) a where
VNil :: Vec 'Zero a
VCons :: a -> Vec n a -> Vec 'Succ n a
-- Type-safe head function
vHead :: Vec ('Succ n) a -> a
vHead (VCons x _) = x
-- Type-safe tail function
vTail :: Vec ('Succ n) a -> Vec n a
vTail (VCons _ xs) = xs
-- Vector concatenation
vAppend :: Vec n a -> Vec m a -> Vec (Add n m) a
vAppend VNil ys = ys
vAppend (VCons x xs) ys = VCons x (vAppend xs ys)
-- Type-level addition
type family Add (n :: Nat) (m :: Nat) :: Nat where
Add 'Zero m = m
Add ('Succ n) m = 'Succ (Add n m)
-- Phantom Types
newtype Tagged tag a = Tagged a deriving (Show)
-- Type safety using tags
data UserID
data ProductID
createUser :: String -> Tagged UserID Int
createUser name = Tagged 123 -- Actually save to DB
createProduct :: String -> Tagged ProductID Int
createProduct name = Tagged 456 -- Actually save to DB
-- Prevent mixing different ID types at type level
-- getUserById :: Tagged UserID Int -> User
-- getProductById :: Tagged ProductID Int -> Product
-- Generalized Algebraic Data Types (GADTs)
data Expr a where
LitInt :: Int -> Expr Int
LitBool :: Bool -> Expr Bool
Add :: Expr Int -> Expr Int -> Expr Int
If :: Expr Bool -> Expr a -> Expr a -> Expr a
-- Type-safe evaluator
eval :: Expr a -> a
eval (LitInt n) = n
eval (LitBool b) = b
eval (Add e1 e2) = eval e1 + eval e2
eval (If cond then_ else_) = if eval cond then eval then_ else eval else_
-- Usage example
exampleExpr :: Expr Int
exampleExpr = If (LitBool True) (Add (LitInt 1) (LitInt 2)) (LitInt 0)
Special Features
Lazy Evaluation
-- Infinite data structures
ones :: [Int]
ones = 1 : ones
naturals :: [Int]
naturals = [0..]
-- Only computed as needed due to lazy evaluation
takeFirst10 :: [Int]
takeFirst10 = take 10 naturals
-- Fibonacci sequence (infinite)
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
-- Infinite list of primes (Sieve of Eratosthenes)
sieve :: [Int] -> [Int]
sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
primes :: [Int]
primes = sieve [2..]
-- Lazy I/O
lazyReadFile :: FilePath -> IO String
lazyReadFile = readFile -- Doesn't load entire file into memory at once
-- Conditional computation (executed only when needed)
expensiveCalculation :: Int -> Int
expensiveCalculation n = if n > 1000 then n * n else 0
conditionalComputation :: Int -> Int
conditionalComputation n =
let expensive = expensiveCalculation n
in if n > 500 then expensive else n
-- Streaming processing with take/drop combinations
processChunks :: [a] -> [[a]]
processChunks [] = []
processChunks xs = take 10 xs : processChunks (drop 10 xs)
-- Parallel processing of infinite lists
parallelSum :: [Int] -> Int
parallelSum xs = foldr (+) 0 xs -- Efficient due to lazy evaluation
Type Classes and Polymorphism
-- Basic type classes
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x /= y = not (x == y)
class Eq a => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
-- Custom type class
class Serializable a where
serialize :: a -> String
deserialize :: String -> Maybe a
instance Serializable Int where
serialize = show
deserialize s = case reads s of
[(x, "")] -> Just x
_ -> Nothing
instance Serializable Bool where
serialize True = "T"
serialize False = "F"
deserialize "T" = Just True
deserialize "F" = Just False
deserialize _ = Nothing
-- Polymorphic functions
identity :: a -> a
identity x = x
first :: (a, b) -> a
first (x, _) = x
swap :: (a, b) -> (b, a)
swap (x, y) = (y, x)
-- Constrained polymorphism
showAndCompare :: (Show a, Ord a) => a -> a -> String
showAndCompare x y = show x ++ " " ++ comparison ++ " " ++ show y
where
comparison = case compare x y of
LT -> "<"
EQ -> "=="
GT -> ">"
-- Higher-Kinded Types
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
(>>=) :: m a -> (a -> m b) -> m b
-- Monad transformers
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
instance Monad m => Functor (ReaderT r m) where
fmap f (ReaderT g) = ReaderT $ \r -> fmap f (g r)
instance Monad m => Applicative (ReaderT r m) where
pure a = ReaderT $ \_ -> pure a
(ReaderT f) <*> (ReaderT g) = ReaderT $ \r -> f r <*> g r
instance Monad m => Monad (ReaderT r m) where
(ReaderT g) >>= f = ReaderT $ \r -> do
a <- g r
runReaderT (f a) r
-- Type families
type family Element c :: * where
Element [a] = a
Element (Maybe a) = a
Element String = Char
class Collection c where
empty :: c
insert :: Element c -> c -> c
member :: Element c -> c -> Bool
instance Collection [a] where
empty = []
insert = (:)
member = elem
Parser Combinators
-- Simple parser library
newtype Parser a = Parser { parse :: String -> Maybe (a, String) }
instance Functor Parser where
fmap f (Parser p) = Parser $ \input -> do
(result, rest) <- p input
return (f result, rest)
instance Applicative Parser where
pure a = Parser $ \input -> Just (a, input)
(Parser pf) <*> (Parser pa) = Parser $ \input -> do
(f, rest1) <- pf input
(a, rest2) <- pa rest1
return (f a, rest2)
instance Monad Parser where
(Parser p) >>= f = Parser $ \input -> do
(result, rest) <- p input
parse (f result) rest
-- Basic parsers
char :: Char -> Parser Char
char c = Parser $ \input ->
case input of
(x:xs) | x == c -> Just (c, xs)
_ -> Nothing
string :: String -> Parser String
string "" = pure ""
string (c:cs) = (:) <$> char c <*> string cs
digit :: Parser Int
digit = Parser $ \input ->
case input of
(x:xs) | x >= '0' && x <= '9' -> Just (read [x], xs)
_ -> Nothing
-- Combinators
(<|>) :: Parser a -> Parser a -> Parser a
(Parser p1) <|> (Parser p2) = Parser $ \input ->
case p1 input of
Nothing -> p2 input
result -> result
many :: Parser a -> Parser [a]
many p = some p <|> pure []
some :: Parser a -> Parser [a]
some p = (:) <$> p <*> many p
-- Number parser
number :: Parser Int
number = read <$> some digit
-- Expression parser example
data Expr = Num Int | Add Expr Expr | Mul Expr Expr deriving (Show)
parseExpr :: Parser Expr
parseExpr = parseAdd
parseAdd :: Parser Expr
parseAdd = chainLeft parseMul (Add <$ char '+')
parseMul :: Parser Expr
parseMul = chainLeft parseFactor (Mul <$ char '*')
parseFactor :: Parser Expr
parseFactor = Num <$> number
<|> (char '(' *> parseExpr <* char ')')
chainLeft :: Parser a -> Parser (a -> a -> a) -> Parser a
chainLeft p op = p >>= rest
where
rest a = (do f <- op
b <- p
rest (f a b)) <|> pure a
-- Usage example
parseExample :: String -> Maybe Expr
parseExample input = fst <$> parse parseExpr input
Versions
Version | Status | Key Features | Release Year |
---|---|---|---|
Haskell 2010 | Current | Current standard, improved module system | 2010 |
Haskell 98 | Legacy | First stable standard | 1998 |
GHC 9.4 | Latest Compiler | Performance improvements, better type errors | 2022 |
GHC 9.2 | Stable Compiler | Record Dot Syntax, type family improvements | 2021 |
Reference Pages
Official Documentation
- Haskell.org - Official site
- GHC User's Guide - GHC User Guide
- Hackage - Package repository
Learning Resources
- Learn You a Haskell - Beginner's guide
- Real World Haskell - Practical Haskell
- Haskell Programming from First Principles - Comprehensive learning book