Introduction to Haskell

  1. What Is Haskell?



  2. Key Features of Haskell

    1. Pure Functional Programming

    2. Lazy Evaluation

    3. Static Strong Typing with Type Inference

    4. Typeclasses

    5. Algebraic Data Types (ADTs)

    6. Monads & Pure I/O


  3. Basic Syntax

  4. def add(a, b):
        return a + b
    
    add a b = a + b
    


  5. Functions Are First-Class

  6. applyTwice f x = f (f x)


  7. Type Annotations (Optional)

  8. add :: Int -> Int -> Int
    add a b = a + b
    


  9. Immutable Variables

  10. x = 10
    -- x = 20   -- INVALID
    


  11. Lists
  12. nums = [1, 2, 3, 4]
    squares = [x * x | x <- [1..5]]


  13. Pattern Matching

  14. describe :: Int -> String
    describe 0 = "Zero"
    describe 1 = "One"
    describe _ = "Other number"
    


  15. Recursion (Fundamental in Haskell)
  16. factorial :: Int -> Int
    factorial 0 = 1
    factorial n = n * factorial (n - 1)
    


  17. Higher-Order Functions
  18. doubleAll xs = map (\x -> x * 2) xs


  19. Typeclasses (Extremely Important)

  20. class Eq a where
        (==) :: a -> a -> Bool
    
    data Color = Red | Blue
    
    instance Eq Color where
        Red == Red = True
        Blue == Blue = True
        _ == _ = False
    


  21. Algebraic Data Types (ADTs)

  22. data Shape
        = Circle Float
        | Rectangle Float Float
    
    area :: Shape -> Float
    area (Circle r) = pi * r * r
    area (Rectangle w h) = w * h
    


  23. The IO Monad (Side Effects in Haskell)

  24. main :: IO ()
    main = do
        putStrLn "Hello!"
        name <- getLine
        putStrLn ("Hi, " ++ name)
    


  25. Lazy Evaluation and Infinite Lists

  26. naturals = [1..]    -- infinite list!
    take 5 naturals   -- [1,2,3,4,5]


  27. How to Get Started

  28. sudo apt install ghc cabal-install
    # OR
    curl -sSL https://get.haskellstack.org/ | sh
    
    ghci
    stack new myproject
    cd myproject
    stack run
    



Using GHCi: The Interactive Haskell Environment

  1. What Is GHCi?



  2. Starting GHCi

  3. ghci
    
    GHCi, version 9.x.x: http://www.haskell.org/ghc/  :? for help
    Prelude>
    


  4. Evaluating Expressions

  5. Prelude> 2 + 3 * 4
    14
    
    Prelude> take 5 [1..]
    [1,2,3,4,5]
    
    Prelude> map (*2) [1..10]
    [2,4,6,8,10,12,14,16,18,20]
    


  6. Checking Types with :type or :t

  7. Prelude> :t 42
    42 :: Num a => a
    
    Prelude> :t map
    map :: (a -> b) -> [a] -> [b]
    


  8. Loading Haskell Files

  9. ghci mycode.hs
    
    Prelude> :reload
    -- or shorthand:
    Prelude> :r
    


  10. Running Main

  11. Prelude> :main
    
    Prelude> :main 10 20
    


  12. Using let to Define Local Bindings

  13. Prelude> let x = 10
    Prelude> x * 2
    20
    
    Prelude> let square n = n * n
    Prelude> square 7
    49
    


  14. Browsing Loaded Modules

  15. Prelude> :show modules
    
    Prelude> :browse
    
    Prelude> :browse Data.List
    


  16. Reloading Automatically

  17. Prelude> :set -fobject-code
    Prelude> :set -fdefer-type-errors
    Prelude> :set -package mtl
    
    Prelude> :reload
    


  18. Importing Modules

  19. Prelude> import Data.List
    Prelude Data.List>
    
    Prelude> import qualified Data.Map as M
    Prelude> M.fromList [(1,"a"), (2,"b")]
    fromList [(1,"a"),(2,"b")]
    


  20. Loading Multiple Files

  21. ghci Main.hs Utils.hs Types.hs
    
    Prelude> :set -i src
    


  22. Debugging with GHCi

  23. Prelude> :break myFunction
    Prelude> :trace main
    Prelude> :history
    Prelude> :continue
    


  24. Useful GHCi Commands

  25. Command Description
    :t expr Show the type of an expression
    :i name Show info about a type or function
    :l file Load a file
    :r Reload current modules
    :main Run the main function
    :q Quit GHCi
    :set -XExtension Enable language extensions
    :browse List contents of current module
    :module + Data.Map Temporarily import a module
    :set prompt "ghci>" Customize the prompt based on your taste


  26. Summary




Comparison Operations in Haskell

  1. What Are Comparison Operations?



  2. The Eq Typeclass: Equality

  3. (==) :: Eq a => a -> a -> Bool
    (/=) :: Eq a => a -> a -> Bool
    

    5 == 5          -- True
    5 /= 3          -- True
    'a' == 'b'      -- False
    [1,2] == [1,2]  -- True
    



  4. The Ord Typeclass: Ordering

  5. (<)  :: Ord a => a -> a -> Bool
    (>)  :: Ord a => a -> a -> Bool
    (<=) :: Ord a => a -> a -> Bool
    (>=) :: Ord a => a -> a -> Bool
    compare :: Ord a => a -> a -> Ordering
    

    data Ordering = LT | EQ | GT
    

    3 < 5        -- True
    "hi" > "ha"  -- True (lexicographical)
    compare 10 7 -- GT
    



  6. Comparing Basic Types

  7. True < False      -- False
    'A' < 'a'         -- True (ASCII/Unicode ordering)
    1.0 == 1.0        -- True
    2.3 >= 2.1        -- True
    

    [1,2,3] < [1,2,4]     -- True
    "abc" > "abb"         -- True
    

    (3, "x") < (3, "y")   -- True
    (2, 5) > (1, 100)      -- True
    


  8. Using max, min, compare

  9. max 3 10            -- 10
    min "apple" "dog"   -- "apple"
    compare 1 1         -- EQ
    


  10. Sort Using Comparison

  11. import Data.List (sort)
    
    sort [3,1,4,1]          -- [1,1,3,4]
    sort ["z", "b", "aa"]   -- ["aa","b","z"]
    


  12. Deriving Eq, Ord for Custom Types

  13. data Color = Red | Green | Blue
      deriving (Eq, Ord, Show)
    
    Red < Blue   -- True (ordering = definition order)
    

    data Point = Point Int Int
      deriving (Eq, Ord, Show)
    
    Point 1 3 < Point 1 4   -- True (lexicographic)
    


  14. Custom Comparison Logic

  15. data Person = Person { name :: String, age :: Int }
    
    instance Eq Person where
        p1 == p2 = age p1 == age p2
    
    instance Ord Person where
        compare p1 p2 = compare (age p1) (age p2)
    


  16. Chaining Comparisons Using Ordering

  17. comparePoints (x1,y1) (x2,y2) =
        compare x1 x2 <> compare y1 y2
    




Introduction to Lists in Haskell

  1. What Are Lists in Haskell?



  2. Creating Lists

  3. [1,2,3]
    ['a','b','c']
    ["hello", "world"]
    

    1 : 2 : 3 : []      -- equals [1,2,3]
    'a' : 'b' : []      -- equals ['a','b']
    



  4. Strings Are Lists of Characters

  5. "hello" == ['h','e','l','l','o']  -- True
    


  6. List Ranges and Sequences

  7. [1..5]         -- [1,2,3,4,5]
    ['a'..'e']     -- ['a','b','c','d','e']
    [0,2..10]      -- [0,2,4,6,8,10] (step of 2)
    

    [1..]          -- infinite list of natural numbers
    take 5 [1..]   -- [1,2,3,4,5]
    


  8. Basic List Operations

  9. head [1,2,3]    -- 1
    

    tail [1,2,3]    -- [2,3]
    

    last [1,2,3]    -- 3
    

    length [1,2,3]  -- 3
    

    [10,20,30] !! 1  -- 20
    

    [1,2] ++ [3,4]   -- [1,2,3,4]
    

    5 : [6,7]   -- [5,6,7]
    


  10. Immutable Structure and Sharing

  11. let xs = [1,2,3]
    let ys = 0 : xs     -- shares tail nodes of xs
    


  12. Pattern Matching on Lists

  13. []       -- empty list
    x : xs   -- head :: tail
    

    describe []     = "empty"
    describe (x:xs) = "head is " ++ show x
    



  14. Higher-Order List Functions

  15. map (*2) [1,2,3]  -- [2,4,6]
    

    filter even [1,2,3,4]  -- [2,4]
    

    foldr (+) 0 [1,2,3]  -- 6
    

    foldl (+) 0 [1,2,3]  -- 6
    


  16. Infinite Lists and Laziness

  17. evens = [0,2..]     -- infinite list
    take 5 evens        -- [0,2,4,6,8]
    


  18. Common Pitfalls

  19. head []     -- Exception
    




List Concatenation in Haskell

  1. What Is List Concatenation?

  2. (++) :: [a] -> [a] -> [a]
    



  3. Basic Examples

  4. [1,2,3] ++ [4,5]       -- [1,2,3,4,5]
    "hi" ++ "!"            -- "hi!"
    ['a'] ++ ['b','c']     -- ['a','b','c']
    


  5. Concatenating Multiple Lists

  6. [1] ++ [2] ++ [3,4]     -- [1,2,3,4]
    

    concat [[1,2], [3], [4,5]]   -- [1,2,3,4,5]
    concat ["hi", " ", "there"]  -- "hi there"
    


  7. Performance Characteristics

  8. -- Slow pattern:
    xs = [1..100000]
    result = xs ++ [100001]   -- O(length xs)
    

    buildSlow xs = xs ++ [1]         -- bad
    buildFast xs = 1 : xs            -- good
    


  9. How ++ Actually Works (Definition)

  10. []     ++ ys = ys
    (x:xs) ++ ys = x : (xs ++ ys)
    



  11. Concatenating Strings

  12. "Hello " ++ "World"      -- "Hello World"
    ['H'] ++ "askell"        -- "Haskell"
    



  13. Using concatMap for Mapping + Concatenation

  14. concatMap (\x -> [x,x]) [1,2,3]
    -- [1,1,2,2,3,3]
    


  15. Concatenation Using List Comprehensions

  16. [ x | x <- [1..3] ] ++ [ x | x <- [4..6] ]
    -- [1,2,3,4,5,6]
    

    concat [[ (x,y) | y <- [1..3] ] | x <- [1..2] ]
    -- [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3)]
    


  17. Concatenation and Infinite Lists

  18. [1,2,3] ++ [4..]
    -- [1,2,3,4,5,6,7,8,...]
    

    [1..] ++ [999]
    -- never reaches 999 (left list never ends)
    



List Comprehension in Haskell

  1. What Are List Comprehensions?



  2. Basic List Comprehension

  3. [ x * 2 | x <- [1,2,3] ]
    -- [2,4,6]
    


  4. Generators

  5. [ (x, y) | x <- [1,2], y <- [10,20] ]
    -- [(1,10),(1,20),(2,10),(2,20)]
    


  6. Filters (Predicates)

  7. [ x | x <- [1..10], even x ]
    -- [2,4,6,8,10]
    

    [ (x,y) | x <- [1..5], y <- [1..5], x < y ]
    -- [(1,2),(1,3),(1,4),(1,5),(2,3),(2,4),(2,5),(3,4),(3,5),(4,5)]
    


  8. Using let Bindings Inside Comprehensions

  9. [ area | r <- [1..5], let area = pi * r^2 ]
    -- [3.14,12.56,28.27,50.27,78.54]
    


  10. Combining Generators, Filters, and Let

  11. [ (x, y, z)
    | x <- [1..5]
    , let y = x * 2
    , z <- [y..10]
    , odd z
    ]
    


  12. List Comprehensions as Map + Filter

  13. map f (filter p xs)
    

    [ x*2 | x <- [1..10], odd x ]
    -- same as:
    map (*2) (filter odd [1..10])
    


  14. Nested Comprehensions

  15. [ [ x*y | y <- [1..3] ] | x <- [1..3] ]
    -- [[1,2,3],[2,4,6],[3,6,9]]
    


  16. List Comprehensions and Strings

  17. [ toUpper c | c <- "hello" ]
    -- "HELLO"
    


  18. Guards and Multiple Filters

  19. [ x | x <- [1..50], x `mod` 7 == 0, x > 20 ]
    -- [28,35,42,49]
    


  20. Using if Expressions Inside Comprehensions

  21. [ if even x then "even" else "odd" | x <- [1..5] ]
    -- ["odd","even","odd","even","odd"]
    


  22. Flattening with concat and Comprehensions

  23. [ (x,y) | x <- [1..2], y <- [1..2] ]
    -- same as:
    concat [ [ (x,y) | y <- [1..2] ] | x <- [1..2] ]
    


  24. Infinite Lists and Laziness

  25. take 10 [ x^2 | x <- [1..] ]
    -- [1,4,9,16,25,36,49,64,81,100]
    



  26. Common Pitfalls

  27. [ x | even x, x <- [1..10] ]
    -- ERROR: x is used before its generator
    

    [ x | x <- [1..10], even x ]
    



Tuples in Haskell

  1. What Are Tuples?

  2. (1, "hello")       -- a pair (2-tuple)
    (True, 3.14, 'x')  -- a triple (3-tuple)
    



  3. Tuple Types

  4. (1, "abc")        -- (Int, String)
    (True, False)     -- (Bool, Bool)
    (1, 2.0, 'c')     -- (Int, Double, Char)
    


  5. The Unit Type: ()

  6. () :: ()
    


  7. Accessing Tuple Elements

  8. let (x, y) = (10, 20)
    -- x = 10, y = 20
    

    let (a, b, c) = (True, 3, "hi")
    -- a = True, b = 3, c = "hi"
    

    fst (3,4)   -- 3
    snd (3,4)   -- 4
    



  9. Tuple Construction

  10. (10, "apple")        -- a pair
    (1, 2, 3, 4)         -- a 4-tuple
    

    coords :: Double -> (Double, Double)
    coords r = (cos r, sin r)
    


  11. Using Tuples in Functions

  12. addPair :: (Int, Int) -> Int
    addPair (a, b) = a + b
    

    divide :: Double -> Double -> (Double, Double)
    divide x y = (x / y, x `mod'` y)
    


  13. Tuples Inside Lists

  14. pairs :: [(Int, String)]
    pairs = [(1, "a"), (2, "b"), (3, "c")]
    

    lookup 2 pairs    -- Just "b"
    


  15. Tuples and List Comprehensions

  16. [ (x, y) | x <- [1..3], y <- [1..3] ]
    -- [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
    

    [ x+y | (x, y) <- [(1,2),(3,4),(5,6)] ]
    -- [3,7,11]
    


  17. Comparisons Between Tuples

  18. (2, 5) < (3, 1)      -- True
    (3, "a") > (3, "Z")  -- True (compare second element)
    


  19. Curried Functions vs. Tupled Arguments

  20. add :: Int -> Int -> Int
    add x y = x + y
    

    addT :: (Int, Int) -> Int
    addT (x, y) = x + y
    




Types and Typeclasses in Haskell

  1. Why Types Matter in Haskell



  2. Basic Built-in Types

  3. 42        :: Int        -- fixed-size integer
    3.14      :: Double     -- double-precision floating point
    True      :: Bool       -- boolean
    'a'       :: Char       -- character
    "hello"   :: String     -- String = [Char]
    

    Prelude> :t 42
    42 :: Num a => a
    



  4. Type Signatures for Functions

  5. name :: TypeOfArg1 -> TypeOfArg2 -> ... -> ResultType
    

    add :: Int -> Int -> Int
    add x y = x + y
    



  6. Type Variables and Polymorphism

  7. identity :: a -> a
    identity x = x
    



  8. Type Constructors and Parameterized Types

  9. Just 5       :: Maybe Int
    Nothing      :: Maybe a
    [1,2,3]      :: [Int]
    Right "ok"   :: Either e String
    Left "err"   :: Either String a
    



  10. Type Synonyms (Type Aliases)

  11. type UserName = String
    type Age      = Int
    
    greet :: UserName -> String
    greet name = "Hello, " ++ name
    


  12. Algebraic Data Types (ADTs)

  13. -- Sum type: a value is either a Circle or a Rectangle
    data Shape
        = Circle    Double          -- radius
        | Rectangle Double Double   -- width height
    
    -- Product type with a single constructor and multiple fields
    data Person = Person
        { name :: String
        , age  :: Int
        }
    


  14. What Is a Typeclass?

  15. class Eq a where
        (==) :: a -> a -> Bool
        (/=) :: a -> a -> Bool
    



  16. Typeclass Constraints

  17. function :: (Constraint1 a, Constraint2 a, Constraint3 b) => a -> b -> ...
    

    showIfEqual :: (Eq a, Show a) => a -> a -> String
    showIfEqual x y =
        if x == y
            then "Equal: " ++ show x
            else "Not equal"
    


  18. Common Standard Typeclasses



  19. Defining Instances: Making a Type Implement a Typeclass

  20. data Color = Red | Green | Blue
    
    instance Eq Color where
        Red   == Red   = True
        Green == Green = True
        Blue  == Blue  = True
        _     == _     = False
    
    instance Show Color where
        show Red   = "Red"
        show Green = "Green"
        show Blue  = "Blue"
    

    Red == Green      -- False
    show Blue         -- "Blue"
    


  21. Deriving Typeclass Instances Automatically

  22. data Color = Red | Green | Blue
        deriving (Eq, Show, Ord)
    


  23. Parametric vs Ad-hoc Polymorphism



  24. Putting It Together: A Small Example

  25. data Point a = Point a a
        deriving (Eq, Show)
    
    -- Distance squared between two points (works for any Num type)
    distSquared :: Num a => Point a -> Point a -> a
    distSquared (Point x1 y1) (Point x2 y2) =
        (x2 - x1) ^ 2 + (y2 - y1) ^ 2
    
    -- Check if two points are the same and show a message
    describePoints :: (Eq a, Show a, Num a) => Point a -> Point a -> String
    describePoints p1 p2 =
        if p1 == p2
            then "Same point: " ++ show p1
            else "Different points: " ++ show p1 ++ " and " ++ show p2
    



Algebraic Data Types (ADTs) in Haskell

  1. What Are ADTs?



  2. Sum Types: Representing Alternatives

  3. data Shape
        = Circle Double             -- radius
        | Rectangle Double Double   -- width height
    
    area :: Shape -> Double
    area (Circle r)        = pi * r^2
    area (Rectangle w h)   = w * h
    


  4. Product Types: Grouping Multiple Values Together

  5. data Person = Person String Int
           --            name   age
    

    greet :: Person -> String
    greet (Person name age) =
        "Hello, " ++ name ++ ", age " ++ show age
    


  6. Record Syntax for Product Types

  7. data User = User
        { username :: String
        , password :: String
        , userAge  :: Int
        }
    

    username (User "a" "b" 21)   -- "a"
    userAge  (User "a" "b" 21)   -- 21
    

    let u = User "bob" "pass" 30
    u { userAge = 31 }
    


  8. Combining Sum + Product: The Real Power of ADTs

  9. data Expr
        = Lit Int                 -- product type (literal)
        | Add Expr Expr           -- product type
        | Mul Expr Expr
    

    eval :: Expr -> Int
    eval (Lit n)     = n
    eval (Add a b)   = eval a + eval b
    eval (Mul a b)   = eval a * eval b
    



  10. Recursive ADTs

  11. data List a
        = Empty
        | Cons a (List a)
    

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


  12. Parameterized ADTs (Generics)

  13. data Maybe a
        = Nothing
        | Just a
    

    Just 5     :: Maybe Int
    Nothing    :: Maybe a
    


  14. Derived Instances for ADTs

  15. data Color
        = Red | Green | Blue
        deriving (Eq, Show, Ord)
    

    Red == Blue    -- False
    show Green     -- "Green"
    Red < Blue     -- True (constructor order)
    


  16. Pattern Matching with ADTs

  17. describeColor :: Color -> String
    describeColor Red   = "Warm color"
    describeColor Green = "Natural color"
    describeColor Blue  = "Cool color"
    



  18. Real-World Example: Handling API Results

  19. data Result a
        = Success a
        | Error String
    

    handle :: Result Int -> String
    handle (Success n) = "Value: " ++ show n
    handle (Error msg) = "Error: " ++ msg
    



Typeclasses in Haskell

  1. What Are Typeclasses?



  2. The Role of Typeclass Constraints

  3. equalMessage :: Eq a => a -> a -> String
    equalMessage x y =
        if x == y then "Equal" else "Not equal"
    

    describe :: (Eq a, Show a) => a -> a -> String
    


  4. Defining a Typeclass

  5. class Printable a where
        toText :: a -> String
    


  6. Creating a Typeclass Instance

  7. data Color = Red | Green | Blue
    
    instance Printable Color where
        toText Red   = "Red"
        toText Green = "Green"
        toText Blue  = "Blue"
    

    toText Red      -- "Red"
    toText Blue     -- "Blue"
    


  8. Automatic Instance Derivation

  9. data Point = Point Int Int
        deriving (Eq, Show)
    



  10. Typeclasses as Constraints on Polymorphic Functions

  11. max3 :: Ord a => a -> a -> a -> a
    max3 a b c = max a (max b c)
    


  12. Multiple Typeclass Constraints

  13. format :: (Show a, Ord a) => a -> a -> String
    format x y =
        if x < y
            then "Ascending: " ++ show x ++ ", " ++ show y
            else "Descending: " ++ show y ++ ", " ++ show x
    


  14. Typeclasses for Parameterized Types

  15. instance Functor Maybe where
        fmap _ Nothing  = Nothing
        fmap f (Just x) = Just (f x)
    



  16. Subclassing in Typeclasses

  17. class Eq a => Ord a where
        (<)  :: a -> a -> Bool
        (>)  :: a -> a -> Bool
        compare :: a -> a -> Ordering
    



  18. Advanced Feature: Default Method Implementations

  19. class Size a where
        size :: a -> Int
        size _ = 1     -- default implementation
    

    data Point = Point Int Int
    
    -- Using the default implementation
    instance Size Point
    
    main = print (size (Point 3 4))   -- prints 1
    

    data Pair a = Pair a a
    
    instance Size (Pair a) where
        size (Pair _ _) = 2   -- custom implementation
    
    main = do
        print (size (Point 3 4))      -- uses default: 1
        print (size (Pair 10 20))     -- uses custom: 2
    


  20. Higher-Kinded Typeclasses



  21. Real-World Example: Defining Equality and Display

  22. data Pair a = Pair a a
    
    instance Eq a => Eq (Pair a) where
        Pair x1 y1 == Pair x2 y2 = x1 == x2 && y1 == y2
    
    instance Show a => Show (Pair a) where
        show (Pair x y) = "Pair(" ++ show x ++ ", " ++ show y ++ ")"
    



Pattern Matching in Haskell

  1. What Is Pattern Matching?



  2. Pattern Matching in Function Definitions

  3. factorial :: Int -> Int
    factorial 0 = 1
    factorial n = n * factorial (n - 1)
    


  4. The Wildcard Pattern _

  5. isZero :: Int -> Bool
    isZero 0 = True
    isZero _ = False
    


  6. Pattern Matching and Tuples

  7. addPair :: (Int, Int) -> Int
    addPair (x, y) = x + y
    

    fstOfTriple :: (a, b, c) -> a
    fstOfTriple (x, _, _) = x
    


  8. Pattern Matching Lists

  9. describe :: [Int] -> String
    describe []        = "empty"
    describe [x]       = "one element"
    describe (x:y:_)   = "at least two elements"
    

    sumList :: [Int] -> Int
    sumList []     = 0
    sumList (x:xs) = x + sumList xs
    


  10. Pattern Matching with Data Constructors (ADTs)

  11. data Shape
        = Circle Double
        | Rectangle Double Double
    
    area :: Shape -> Double
    area (Circle r) = pi * r^2
    area (Rectangle w h) = w * h
    


  12. Pattern Matching with Records

  13. data User = User
        { name :: String
        , age  :: Int
        }
    
    describeUser :: User -> String
    describeUser User { name = n, age = a } =
        n ++ " is " ++ show a ++ " years old"
    


  14. As-patterns

  15. describeList :: [a] -> String
    describeList xs@(x:_) = "first element: " ++ show x ++ ", full list: " ++ show xs
    describeList []       = "empty list"
    



  16. Pattern Matching in case Expressions

  17. describeBool :: Bool -> String
    describeBool b =
        case b of
            True  -> "yes"
            False -> "no"
    


  18. Guards Together with Pattern Matching

  19. classify :: Int -> String
    classify n
        | n < 0     = "negative"
        | n == 0    = "zero"
        | otherwise = "positive"
    



  20. Matching Failure: Why Order Matters

  21. bad :: [a] -> String
    bad (x:xs) = "nonempty"
    bad []     = "empty"
    -- The order here is fine.
    

    bad2 :: [a] -> String
    bad2 []     = "empty"
    bad2 (x:xs) = "nonempty"
    

    bad3 :: [a] -> String
    bad3 xs = "always matches first!"
    bad3 [] = "never reached"
    



  22. Irrefutable Patterns

  23. lazyTuple :: (a, b) -> String
    lazyTuple ~(x, y) = "always matches"
    


  24. Pattern Matching in List Comprehensions

  25. pairs :: [(Int, Int)]
    pairs = [ (x, y) | (x, y) <- [(1,2), (3,4)] ]
    

    firsts :: [(Int, Int)] -> [Int]
    firsts xs = [ x | (x, _) <- xs ]
    


  26. Pattern Matching and Exhaustiveness Checking

  27. describeMaybe :: Maybe Int -> String
    describeMaybe (Just n) = "number"
    describeMaybe Nothing  = "none"
    



Guards in Haskell

  1. What Are Guards?




  2. Basic Example of Guards

  3. sign :: Int -> String
    sign n
        | n < 0     = "negative"
        | n == 0    = "zero"
        | otherwise = "positive"
    


  4. Guards with Multiple Conditions

  5. bmiInfo :: Double -> String
    bmiInfo bmi
        | bmi < 18.5                     = "underweight"
        | bmi >= 18.5 && bmi < 25.0      = "normal"
        | bmi >= 25.0 && bmi < 30.0      = "overweight"
        | otherwise                      = "obese"
    


  6. Pattern Matching Combined with Guards

  7. classifyList :: [a] -> String
    classifyList [] = "empty"
    classifyList xs
        | length xs == 1 = "singleton"
        | length xs < 5  = "short list"
        | otherwise      = "long list"
    



  8. Using Guards in case Expressions

  9. describe :: Int -> String
    describe n = case n of
        _ | n < 0     -> "negative"
        _ | n == 0    -> "zero"
        _ | otherwise -> "positive"
    



  10. Guards with Let Bindings

  11. bmiTell :: Double -> Double -> String
    bmiTell weight height
        | bmi < 18.5 = "underweight"
        | bmi < 25.0 = "normal"
        | bmi < 30.0 = "overweight"
        | otherwise  = "obese"
      where
        bmi = weight / (height ^ 2)
    
    -- Equivalent but repetitive:
    bmiTell w h
        | w / (h ^ 2) < 18.5 = "underweight"
        | w / (h ^ 2) < 25.0 = "normal"
        | w / (h ^ 2) < 30.0 = "overweight"
        | otherwise          = "obese"
    

    bmiTell2 weight height
        | let bmi = weight / (height ^ 2)
        , bmi < 18.5 = "underweight"
        | otherwise  = "others"
    


  12. Using otherwise Safely

  13. otherwise = True
    
    describe n
        | n > 10    = "big"
        | otherwise = "small or equal to 10"
    


  14. Guards vs If/Else



  15. Guards with Multiple Arguments

  16. max3 :: Ord a => a -> a -> a -> a
    max3 x y z
        | x >= y && x >= z = x
        | y >= x && y >= z = y
        | otherwise        = z
    


  17. Guards with Pattern Guards (Advanced)

  18. f x
        | Just y <- lookup x table = "found " ++ show y
        | otherwise                = "not found"
    



  19. Example: Combining Everything

  20. triangleType :: (Eq a, Ord a, Num a) => a -> a -> a -> String
    triangleType a b c
        | a + b <= c || b + c <= a || a + c <= b = "not a triangle"
        | a == b && b == c                       = "equilateral"
        | a == b || b == c || a == c             = "isosceles"
        | otherwise                              = "scalene"
    



Built-in Types in Haskell

  1. Big Picture



  2. Bool: Boolean Type

  3. data Bool = False | True
    

    (&&) :: Bool -> Bool -> Bool
    (||) :: Bool -> Bool -> Bool
    not  :: Bool -> Bool
    
    True  && False   -- False
    True  || False   -- True
    not True        -- False
    



  4. Char: Unicode Characters

  5. 'a'  :: Char
    'Z'  :: Char
    '\n' :: Char
    '中' :: Char
    

    isAlpha  :: Char -> Bool
    isDigit  :: Char -> Bool
    toUpper  :: Char -> Char
    toLower  :: Char -> Char
    

    import Data.Char (toUpper, isDigit)
    
    toUpper 'a'        -- 'A'
    isDigit '3'        -- True
    isDigit 'x'        -- False
    


  6. String: Text Built from [Char]

  7. type String = [Char]
    

    "hello"       :: String
    "λ-calculus"  :: String
    

    length :: [a] -> Int
    
    length "haskell"       -- 7
    'h' : "askell"         -- "haskell"
    "foo" ++ "bar"         -- "foobar"
    



  8. Numeric Tower Overview

  9. class Num a where ...
    class Real a where ...
    class Integral a where ...
    class Fractional a where ...
    class Floating a where ...
    class RealFrac a where ...
    class RealFloat a where ...
    

    Integral ⊆ Real ⊆ Num
    Fractional ⊆ Num
    Floating   ⊆ Fractional
    RealFrac   ⊆ Real & Fractional
    RealFloat  ⊆ RealFrac & Floating
    

    5   :: Num a => a         -- can be Int, Integer, Double, ...
    3.5 :: Fractional a => a  -- can be Float or Double
    


  10. Integral Types

  11. 42    :: Int
    (-10) :: Int
    

    123456789012345678901234567890 :: Integer
    

    import Data.Int
    
    Int8, Int16, Int32, Int64  -- signed fixed-width
    

    import Data.Word
    
    Word8, Word16, Word32, Word64  -- unsigned
    

    import Numeric.Natural
    
    0    :: Natural
    123  :: Natural
    

    class (Real a, Enum a) => Integral a where
        quot, rem, div, mod :: a -> a -> a
        ...
    



  12. Fractional & Floating Types

  13. 3.14   :: Float
    2.718  :: Double
    

    class (Num a) => Fractional a where
        (/)          :: a -> a -> a
        fromRational :: Rational -> a
    

    type Rational = Ratio Integer
    

    import Data.Ratio
    
    1 % 3        :: Rational
    (1 % 3) + (1 % 6)  -- 1 % 2  (exact 1/2)
    



  14. Complex Numbers

  15. import Data.Complex
    
    (3 :+ 4)        :: Complex Double
    magnitude (3 :+ 4)   -- 5.0
    

    data Complex a = !a :+ !a
    



  16. Lists: [a] and Lazy Sequences

  17. data [] a = [] | a : [a]
    

    [1,2,3]        :: [Int]
    []             :: [a]
    1 : 2 : 3 : [] :: [Int]
    

    head, tail     :: [a] -> a / [a]
    length         :: [a] -> Int
    (++)           :: [a] -> [a] -> [a]
    map, filter    :: (a -> b) -> [a] -> [b] / (a -> Bool) -> [a] -> [a]
    

    [1..]              -- infinite list of Ints
    take 5 [1..]       -- [1,2,3,4,5]
    



  18. Tuples and the Unit Type ()

  19. (1, "hi")         :: (Int, String)
    (True, 3.14, 'x') :: (Bool, Double, Char)
    

    () :: ()
    

    print :: Show a => a -> IO ()
    

    fst :: (a, b) -> a
    snd :: (a, b) -> b
    


  20. Maybe a: Optional Values

  21. data Maybe a = Nothing | Just a
    

    Just 5      :: Maybe Int
    Nothing     :: Maybe a
    

    safeHead :: [a] -> Maybe a
    safeHead []    = Nothing
    safeHead (x:_) = Just x
    



  22. Either e a: Two-way Choice (Often for Errors)

  23. data Either a b = Left a | Right b
    

    parseInt :: String -> Either String Int
    parseInt s =
        case reads s of
            [(n, "")] -> Right n
            _         -> Left "not a number"
    



  24. Ordering: Result of Comparisons

  25. data Ordering = LT | EQ | GT
    

    compare 3 5  -- LT
    compare 5 5  -- EQ
    compare 7 2  -- GT
    



  26. Function Types: a -> b

  27. increment :: Int -> Int
    increment x = x + 1
    

    add :: Int -> Int -> Int
    add x y = x + y
    
    -- add has type: Int -> (Int -> Int)
    

    applyTwice :: (a -> a) -> a -> a
    applyTwice f x = f (f x)
    

    ( -> ) :: * -> * -> *
    


  28. IO a: Side Effects and the Outside World

  29. getLine  :: IO String
    putStrLn :: String -> IO ()
    readFile :: FilePath -> IO String
    

    main :: IO ()
    main = do
        putStrLn "What is your name?"
        name <- getLine
        putStrLn ("Hello, " ++ name)
    



  30. Type Constructors & Kinds for Built-in Types

  31. Maybe     :: * -> *
    Maybe Int :: *
    
    Either :: * -> * -> *
    Either String Int :: *
    



  32. Laziness, Memory, and Performance Notes




Imports and Modules in Haskell

  1. What Does import Do in Haskell?




  2. Basic import Syntax

  3. import Module.Name
    

    import Data.Maybe
    import System.IO
    import Control.Monad
    



  4. Importing Specific Names

  5. import Data.List (sort, nub)
    
    import Data.Maybe (Maybe(..))
    -- imports the type Maybe and its constructors: Just, Nothing
    
    import Data.Either (Either(Left, Right))
    


  6. Hiding Names with hiding

  7. import Data.List hiding (sort)
    

    import Prelude hiding (head, tail)
    



  8. Qualified Imports

  9. import qualified Data.Map
    
    example :: Data.Map.Map String Int
    example = Data.Map.fromList [("a", 1), ("b", 2)]
    



  10. Qualified Imports with as (Aliases)

  11. import qualified Data.Map as M
    
    example :: M.Map String Int
    example = M.fromList [("a", 1), ("b", 2)]
    


  12. Combining Qualified, Explicit, and Hiding

  13. -- 1. Qualified with explicit import list
    import qualified Data.Map as M (Map, fromList, lookup)
    
    -- 2. Unqualified with explicit list
    import Data.List (sort, nub)
    
    -- 3. Qualified hiding some names (less common)
    import qualified Data.List as L hiding (nub)
    



  14. Dealing with Name Clashes

  15. -- Strategy 1: qualified import
    import qualified Data.Map as M
    
    -- Strategy 2: hide conflicting names
    import Prelude hiding (lookup)
    import qualified Data.Map as M
    

    import qualified Data.Map as M
    import qualified Data.List as L
    
    foo :: Maybe Int
    foo =
        let m = M.fromList [("a", 1)]
        in  M.lookup "a" m   -- clearly from Data.Map
    
    bar :: Maybe Int
    bar =
        L.lookup "a" [("a", 1)]  -- from Data.List
    


  16. The Prelude and Turning It Off

  17. -- Implicitly:
    import Prelude
    

    {-# LANGUAGE NoImplicitPrelude #-}
    module Main where
    
    import MyCustomPrelude
    



  18. Importing Your Own Modules

  19. -- File: src/MyApp/Utils/Math.hs
    module MyApp.Utils.Math where
    
    square :: Int -> Int
    square x = x * x
    

    -- File: src/MyApp/Main.hs
    module MyApp.Main where
    
    import MyApp.Utils.Math (square)
    
    foo :: Int
    foo = square 10
    



  20. import in GHCi

  21. Prelude> import Data.List
    Prelude Data.List> sort [3,1,2]
    [1,2,3]
    

    Prelude> :m + Data.List Data.Maybe
    



  22. Safe Imports (Safe Haskell)

  23. import safe Data.List
    



Higher-Order Functions in Haskell

  1. What Are Higher-Order Functions (HOFs)?



  2. Functions as Arguments

  3. applyTwice :: (a -> a) -> a -> a
    applyTwice f x = f (f x)
    
    applyTwice (+1) 3   -- 5
    applyTwice (*2) 4   -- 16
    



  4. Functions Returning Functions

  5. makeAdder :: Int -> (Int -> Int)
    makeAdder n = \x -> x + n
    
    add10 = makeAdder 10      -- add10 :: Int -> Int
    add10 5                   -- 15
    

    makeMultiplier :: Int -> (Int -> Int)
    makeMultiplier m = \x -> x * m
    
    double = makeMultiplier 2
    double 21        -- 42
    


  6. Anonymous Functions (Lambdas)

  7. map (\x -> x * 2) [1,2,3]   -- [2,4,6]
    

    \x y -> x + y
    


  8. map: Apply a Function to Each Element

  9. map :: (a -> b) -> [a] -> [b]
    
    map (*2) [1,2,3]    -- [2,4,6]
    map show [1,2,3]    -- ["1","2","3"]
    

    fmap :: Functor f => (a -> b) -> f a -> f b
    


  10. filter: Keep Elements That Match a Predicate

  11. filter :: (a -> Bool) -> [a] -> [a]
    
    filter odd [1..10]       -- [1,3,5,7,9]
    filter (\x -> x > 5) [3,6,7]  -- [6,7]
    



  12. foldr and foldl: Reduce a List

  13. foldr :: (a -> b -> b) -> b -> [a] -> b
    
    foldr (+) 0 [1,2,3]   -- 6
    foldr (:) [] [1,2,3] -- [1,2,3]
    

    foldl :: (b -> a -> b) -> b -> [a] -> b
    
    foldl (+) 0 [1,2,3]  -- 6
    

    import Data.List (foldl')
    foldl' (+) 0 [1..]   -- will run indefinitely but without memory leak
    


  14. Function Composition with .

  15. (.) :: (b -> c) -> (a -> b) -> (a -> c)
    
    (f . g) x = f (g x)
    

    (negate . abs) (-10)   -- -10
    map (show . (*2)) [1,2,3]  -- ["2","4","6"]
    


  16. Function Application with $

  17. ($) :: (a -> b) -> a -> b
    f $ x = f x
    

    sum (map abs [1,-2,3])
    sum $ map abs [1,-2,3]
    



  18. Partial Application

  19. add :: Int -> Int -> Int
    add x y = x + y
    
    addFive = add 5     -- addFive :: Int -> Int
    addFive 10          -- 15
    



  20. Sections: Turning Operators into Functions

  21. (+) 3      -- \x -> 3 + x
    (3 +)      -- same as above
    (+ 3)      -- \x -> x + 3
    (*2)       -- \x -> x * 2
    



  22. Zip Functions

  23. zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    
    zipWith (+) [1,2,3] [4,5,6]    -- [5,7,9]
    zipWith max [1,5,2] [3,2,8]    -- [3,5,8]
    



  24. Higher-Order Patterns in Real Projects


  25. validate :: (a -> Bool) -> String -> a -> Either String a
    validate p msg x =
        if p x then Right x else Left msg
    
    isPositive = validate (> 0) "not positive"
    isEven     = validate even  "not even"
    
    isEven 4       -- Right 4
    isPositive (-1) -- Left "not positive"
    


  26. Using HOFs to Create Pipelines

  27. processNumbers =
          map (*2)
        . filter odd
        . map (+1)
    

    processNumbers [1,2,3,4]  -- [4,8]
    



Lambda Expressions (Anonymous Functions) in Haskell

  1. What Are Lambda Expressions?



  2. Basic Syntax

  3. \x -> x + 1
    

    addOne x = x + 1
    

    (\x -> x + 1) 5   -- 6
    


  4. Multiple Arguments

  5. \x y -> x + y
    

    add x y = x + y
    

    (\x -> \y -> x + y)
    


  6. Lambdas Inside Higher-Order Functions

  7. map (\x -> x * 2) [1,2,3]
    -- [2,4,6]
    
    filter (\x -> x > 5) [3,4,5,6,7]
    -- [6,7]
    

    map (\c -> toUpper c) "lambda"
    -- "LAMBDA"
    


  8. Lambdas with Pattern Matching

  9. \ (x, y) -> x + y
    

    map (\(x,y) -> x * y) [(2,3), (4,5)]
    -- [6,20]
    

    \ (x:_) -> x
    



  10. Lambdas in Let and Where Bindings



  11. Lambda Case (\case)



  12. Lambda Patterns with \\ Syntax (Multi-Clause Lambdas)

  13. \case
        (x,y) -> x
        _     -> 0
    



  14. Common Lambda Shorthands

  15. \x -> x + 1      ==  (+1)
    \x -> 1 + x      ==  (1+)
    \x -> x * y      ==  (*y)
    \x -> f (g x)    ==  (f . g)
    



  16. Examples of Real-World Lambda Usage

  17. import Data.List (sortBy)
    
    sortBy (\a b -> compare (length a) (length b)) ["hi", "hello", "a"]
    -- ["a","hi","hello"]
    

    map (\x -> read x :: Int) ["1","2","3"]
    -- [1,2,3]
    

    let pipeline = filter (\x -> x > 3) . map (\x -> x * 2)
    pipeline [1,2,3,4]
    -- [8]
    


  18. Do Lambdas Have Types?

  19. :t \x -> x + 1
    -- :: Num a => a -> a
    

    (\x -> x + 1) :: Int -> Int
    



Modules in Haskell

  1. What Are Modules in Haskell?



  2. Basic Module Declaration

  3. module MyModule where
    
    x = 42
    



  4. Export Lists

  5. module Math.Utils (square, cube) where
    
    square x = x * x
    cube x   = x * x * x
    secret   = 123   -- not exported
    
    module Math.Utils where
    


  6. Exporting Types and Constructors

  7. module Shapes
        ( Shape(Circle, Rectangle)
        , area
        ) where
    
    data Shape = Circle Double | Rectangle Double Double
    area (Circle r)       = pi * r * r
    area (Rectangle w h)  = w * h
    

    module Shapes (Shape(..)) where
    


  8. Importing Modules (Short Summary)

  9. import Data.List (sort, nub)
    import qualified Data.Map as M
    



  10. Hierarchical Modules

  11. module MyApp.Utils.Math where
    

    MyApp/
     └─ Utils/
         └─ Math.hs
    



  12. The Prelude Module

  13. import Prelude
    

    {-# LANGUAGE NoImplicitPrelude #-}
    module Main where
    



  14. Re-exporting from Modules

  15. module MyPrelude
        ( module Data.List
        , module Data.Maybe
        ) where
    
    import Data.List
    import Data.Maybe
    

    import MyPrelude
    



  16. Qualified Re-exports

  17. module Operators (module M) where
    import qualified MyApp.Operators as M
    


  18. Internal Modules

  19. src/
     ├─ MyLib.hs
     ├─ MyLib/
     │   ├─ Core.hs
     │   ├─ Utils.hs
     │   └─ Internal/
     │       └─ Helpers.hs
    



  20. Module Initialization and Side Effects

  21. main :: IO ()
    main = putStrLn "Program started"
    


  22. Modules and Name Resolution

  23. import qualified Data.Map as M
    
    M.lookup "a" (M.fromList [("a",1)])
    



  24. Modules for Namespacing

  25. -- In File A:
    module Foo where
    x = 10
    
    -- In File B:
    module Bar where
    x = 20
    

    import qualified Foo
    import qualified Bar
    
    Foo.x    -- 10
    Bar.x    -- 20
    


  26. Modules and Cabal/Stack Projects

  27. exposed-modules:
        MyLib
        MyLib.Core
    other-modules:
        MyLib.Internal.Helpers
    


  28. Creating Your Own Module

  29. module Utils.StringTools
        ( capitalize
        , reverseWords
        ) where
    
    import Data.Char (toUpper)
    
    capitalize :: String -> String
    capitalize [] = []
    capitalize (x:xs) = toUpper x : xs
    
    reverseWords :: String -> String
    reverseWords = unwords . reverse . words
    

    module Main where
    
    import Utils.StringTools
    
    main = putStrLn (capitalize "hello world")
    



Deriving Instances in Haskell

  1. What Does "Deriving" Mean in Haskell?

  2. data Color = Red | Green | Blue
    
    instance Eq Color where
        Red   == Red   = True
        Green == Green = True
        Blue  == Blue  = True
        _     == _     = False
    
    instance Show Color where
        show Red   = "Red"
        show Green = "Green"
        show Blue  = "Blue"
    

    data Color = Red | Green | Blue
        deriving (Eq, Show)
    



  3. Basic Deriving Syntax

  4. data Point = Point Int Int
        deriving (Eq, Show)
    



  5. Example: Deriving Eq and Show for an ADT

  6. data Expr
        = Lit Int
        | Add Expr Expr
        | Mul Expr Expr
        deriving (Eq, Show)
    

    e1 :: Expr
    e1 = Add (Lit 1) (Mul (Lit 2) (Lit 3))
    
    e2 :: Expr
    e2 = Add (Lit 1) (Mul (Lit 2) (Lit 3))
    
    e3 :: Expr
    e3 = Add (Lit 1) (Lit 2)
    
    e1 == e2       -- True
    e1 == e3       -- False
    show e1        -- "Add (Lit 1) (Mul (Lit 2) (Lit 3))"
    



  7. Deriving Enum and Bounded

  8. data Color = Red | Green | Blue
        deriving (Eq, Ord, Show, Enum, Bounded)
    
    allColors :: [Color]
    allColors = [minBound .. maxBound]
    -- [Red,Green,Blue]
    
    succ Red    -- Green
    pred Blue   -- Green
    fromEnum Red   -- 0
    fromEnum Blue  -- 2
    



  9. Deriving for Parameterized Types

  10. data Pair a = Pair a a
        deriving (Eq, Ord, Show, Functor)
    

    {-# LANGUAGE DeriveFunctor #-}
    
    data Tree a
        = Leaf a
        | Node (Tree a) (Tree a)
        deriving (Eq, Show, Functor)
    

    fmap (+1) (Leaf 3)     -- Leaf 4
    


  11. Deriving for Newtypes

  12. newtype UserId = UserId Int
        deriving (Eq, Ord, Show)
    



  13. Standalone Deriving

  14. {-# LANGUAGE StandaloneDeriving #-}
    

    data Foo a = Foo a
    
    -- later in the file, or even another module (with some restrictions):
    deriving instance Eq a => Eq (Foo a)
    deriving instance Show a => Show (Foo a)
    



  15. Deriving Strategies: stock, newtype, anyclass, via

  16. {-# LANGUAGE DerivingStrategies #-}
    

    newtype Age = Age Int
        deriving stock    (Eq, Show)
        deriving newtype  (Ord, Num)
    



  17. Example: Newtype Deriving for Numeric Behavior

  18. {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    
    newtype Distance = Distance Double
        deriving (Eq, Ord, Show, Num, Fractional)
    

    d1 :: Distance
    d1 = 10
    
    d2 :: Distance
    d2 = 2.5
    
    d1 + d2         -- Distance 12.5
    d1 * 2          -- Distance 20.0
    



  19. Deriving Generic / Generic1

  20. {-# LANGUAGE DeriveGeneric #-}
    
    import GHC.Generics (Generic)
    
    data User = User
        { name :: String
        , age  :: Int
        } deriving (Show, Generic)
    



  21. Deriving Anyclass

  22. {-# LANGUAGE DeriveAnyClass #-}
    {-# LANGUAGE DeriveGeneric  #-}
    
    import GHC.Generics (Generic)
    
    class MyClass a where
        describe :: a -> String
        describe _ = "default"
    
    data Foo = Foo Int
        deriving (Generic, MyClass)
    



  23. Deriving Via (Advanced)

  24. {-# LANGUAGE DerivingVia #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    
    import Data.Monoid (Sum(..))
    
    newtype Score = Score Int
        deriving (Eq, Show)
        deriving (Semigroup, Monoid) via (Sum Int)
    




The => Operator (Constraint Arrow) in Haskell

  1. What Is the => Operator?




  2. Constraints Are Typeclass Requirements

  3. ClassName typeVariable
    

    Eq a        -- a supports equality
    Ord a       -- a supports ordering
    Num a       -- a acts like a number
    Monad m     -- m is a monad
    Functor f   -- f is a functor
    

    Eq a => a -> a -> Bool
    



  4. Multiple Constraints Using a Tuple

  5. (Eq a, Show a) => a -> String
    



  6. How GHC Interprets the Constraint Arrow

  7. Eq a => a -> a -> Bool
    



  8. Example: Using a Constraint in a Function

  9. isIn :: Eq a => a -> [a] -> Bool
    isIn x xs = any (== x) xs
    



  10. Constraint Arrow with Polymorphic Functions

  11. compareAndShow :: (Ord a, Show a) => a -> a -> String
    compareAndShow x y =
        if x > y
        then show x ++ " > " ++ show y
        else if x == y
        then show x ++ " == " ++ show y
        else show x ++ " < " ++ show y
    


  12. => vs ->

  13. Symbol Meaning
    -> Function arrow: maps inputs to outputs.
    => Constraint arrow: says that certain typeclasses must be satisfied.

    foo :: (Eq a, Show a) => a -> a -> String
    


  14. Constraint Arrow in Typeclass Definitions

  15. class (Eq a, Show a) => MyClass a where
        foo :: a -> String
    



  16. Constraint Arrow in Instance Declarations

  17. instance (Eq a, Show a) => Show (Pair a) where
        show (Pair x y) = "(" ++ show x ++ "," ++ show y ++ ")"
    



  18. Constraint Arrow Inside Type Synonyms (Using ConstraintKinds)

  19. {-# LANGUAGE ConstraintKinds #-}
    
    type Number a = (Num a, Ord a)
    

    foo :: Number a => a -> a -> a
    foo x y = if x > y then x else y
    


  20. Constraint Arrow in Higher-Kinded Types

  21. class Functor f => Applicative f where
        pure  :: a -> f a
        (<*>) :: f (a -> b) -> f a -> f b
    



  22. Constraint Arrow with Forall Quantifiers (Advanced)

  23. {-# LANGUAGE RankNTypes #-}
    
    bar :: (forall a. Show a => a -> String) -> (String, String)
    bar f = (f 3, f "hi")
    




Kinds * and * -> * in Haskell

  1. What Are Kinds?

  2. -- Value has a type:
    42       :: Int
    
    -- Type has a kind:
    Int      :: *
    Maybe    :: * -> *
    Either   :: * -> * -> *
    



  3. Kind *: Concrete (Fully Applied) Types

  4. Int       :: *
    Bool      :: *
    Char      :: *
    [Int]     :: *
    Maybe Int :: *
    Either String Int :: *
    

    x :: Int
    x = 42
    
    name :: String
    name = "haskell"
    
    maybeNum :: Maybe Int
    maybeNum = Just 10
    



  5. Kind * -> *: Type Constructors

  6. Maybe :: * -> *
    []    :: * -> *
    IO    :: * -> *
    

    Maybe Int  :: *
    Maybe Bool :: *
    
    [Char]   :: *
    IO Int   :: *
    

    Maybe   :: * -> *
    Maybe a :: *   -- when a :: *
    


  7. Higher-Kinded Types: * -> * -> * and Beyond

  8. Either :: * -> * -> *
    (,)    :: * -> * -> *
    

    Either String Int :: *
    
    Either String  :: * -> *   -- partially applied
    Either         :: * -> * -> *
    



  9. Why * -> * Matters: Typeclasses Like Functor and Monad

  10. class Functor f where
        fmap :: (a -> b) -> f a -> f b
    

    instance Functor Maybe where ...
    instance Functor [] where ...
    instance Functor IO where ...
    instance Functor (Either e) where ...
    



  11. Using :kind in GHCi

  12. Prelude> :k Int
    Int :: *
    
    Prelude> :k Maybe
    Maybe :: * -> *
    
    Prelude> :k Maybe Int
    Maybe Int :: *
    
    Prelude> :k Either
    Either :: * -> * -> *
    
    Prelude> :k Either String
    Either String :: * -> *
    



  13. * vs Type

  14. import Data.Kind (Type)
    
    -- These are conceptually the same:
    Int   :: Type
    Maybe :: Type -> Type
    



  15. Advanced: Beyond * (Other Kinds)

  16. {-# LANGUAGE DataKinds #-}
    
    -- Promoted values become types, and types get more specific kinds
    data Color = Red | Green | Blue
    -- Kinds: Color, not just *
    




Input and Output in Haskell

  1. Why Is IO Special in Haskell?




  2. The IO Type

  3. IO :: * -> *
    

    IO Int       -- an action that returns an Int
    IO String    -- an action that returns a String
    IO ()        -- an action with no meaningful result
    



  4. Do-notation: Sequencing IO

  5. main :: IO ()
    main = do
        putStrLn "Enter your name:"
        name <- getLine
        putStrLn ("Hello, " ++ name ++ "!")
    

    x <- 3           -- ❌ illegal, 3 is not an IO action
    y <- getLine     -- ✔️ OK
    


  6. Basic IO Operations

  7. putStr    :: String -> IO ()
    putStrLn  :: String -> IO ()
    print     :: Show a => a -> IO ()
    
    print 123         -- outputs "123"
    putStr "hi"       -- outputs hi
    putStrLn "hi"     -- outputs hi\n
    

    getLine :: IO String
    getChar :: IO Char
    getContents :: IO String   -- lazy input until EOF
    


  8. Reading and parsing input

  9. main :: IO ()
    main = do
        putStrLn "Enter a number:"
        s <- getLine
        let n = read s :: Int
        print (n + 10)
    



  10. Lazy IO vs Strict IO



  11. IO as a Monad

  12. main =
        getLine >>= \name ->
        putStrLn ("Hello " ++ name)
    

    main = do
        name <- getLine
        putStrLn ("Hello " ++ name)
    


  13. Chaining IO Actions Without Extracting Values

  14. putStrLn "A"
        >> putStrLn "B"
        >> putStrLn "C"
    

    do
        putStrLn "A"
        putStrLn "B"
        putStrLn "C"
    


  15. Working with Files

  16. readFile  :: FilePath -> IO String
    writeFile :: FilePath -> String -> IO ()
    appendFile :: FilePath -> String -> IO ()
    
    openFile  :: FilePath -> IOMode -> IO Handle
    hGetLine  :: Handle -> IO String
    hPutStrLn :: Handle -> String -> IO ()
    hClose    :: Handle -> IO ()
    

    main = do
        content <- readFile "data.txt"
        putStrLn "File contents:"
        putStrLn content
    

    main = do
        h <- openFile "log.txt" AppendMode
        hPutStrLn h "new log entry"
        hClose h
    


  17. Exception Handling in IO

  18. import Control.Exception (catch, IOException)
    
    main = do
        content <- catch (readFile "xxx.txt")
                        (\e -> do let _ = e :: IOException
                                  putStrLn "File not found!"
                                  return "")
        putStrLn content
    


  19. IO with pure functions

  20. process :: String -> Int
    process = length
    
    main = do
        s <- getLine
        print (process s)
    



  21. Returning values from IO

  22. main = do
        let x = 10
        y <- return (x * 2)
        print y
    

    return x :: IO x
    


  23. Infinite IO Loops

  24. forever :: IO a -> IO b
    
    main = forever $ do
        putStrLn "Enter something:"
        s <- getLine
        print (length s)
    


  25. Sequencing a List of IO Actions

  26. sequence  :: [IO a] -> IO [a]
    mapM      :: (a -> IO b) -> [a] -> IO [b]
    mapM_     :: (a -> IO b) -> [a] -> IO ()
    traverse  :: Applicative f => (a -> f b) -> [a] -> f [b]
    
    main = do
        names <- mapM (\_ -> getLine) [1..3]
        print names
    



Functors, Applicative Functors, and Monoids in Haskell

  1. Overview



  2. Functors: Mapping Over a Structure

  3. class Functor f where
        fmap :: (a -> b) -> f a -> f b
    

    fmap (+1) [1,2,3]           -- [2,3,4]
    fmap (*2) (Just 10)         -- Just 20
    fmap (*2) Nothing           -- Nothing
    fmap reverse (Right "xy")   -- Right "yx"
    



  4. Applicative Functors: Combining Contextual Values

  5. class Functor f => Applicative f where
        pure  :: a -> f a
        (<*>) :: f (a -> b) -> f a -> f b
    

    pure (+1) <*> Just 10    -- Just 11
    pure (+1) <*> Nothing    -- Nothing
    
    [(+1), (*2)] <*> [10,20]   -- [11,21,12,22]
    



  6. Applicative with Syntactic Sugar: <$> and <*>

  7. Just (+) <*> Just 3 <*> Just 5   -- Just 8
    
    (+) <$> Just 3 <*> Just 5        -- Just 8
    


  8. Applicative Examples

  9. pair :: IO (String, String)
    pair = (,) <$> getLine <*> getLine
    


    User <$> validateName name
         <*> validateAge age
         <*> validateEmail email
    


  10. Monoids: Combining Values

  11. class Monoid m where
        mempty  :: m
        mappend :: m -> m -> m       -- (deprecated in favor of <>)
        (<>)    :: m -> m -> m
    



  12. Common Monoid Instances

  13. mempty  = []
    a <> b  = a ++ b
    

    Sum Int:
        mempty = 0
        mappend = (+)
    
    Product Int:
        mempty = 1
        mappend = (*)
    

    instance Monoid a => Monoid (Maybe a) where
        mempty = Just mempty
        Just x  <> Just y  = Just (x <> y)
        _       <> _       = Nothing
    



  14. Monoid in action: folding

  15. mconcat [[1,2], [3], [4,5]]    -- [1,2,3,4,5]
    mconcat [Sum 1, Sum 2, Sum 10] -- Sum 13
    

    foldMap Sum [1,2,3,4]   -- Sum 10
    foldMap (:[]) [1,2,3]   -- [1,2,3]
    


  16. How Functor, Applicative, and Monoid Relate



  17. Example: Validation with Applicative and Monoid Errors

  18. import Data.Monoid (Sum(..))
    
    validate :: Int -> Either [String] Int
    validate n
        | n < 0     = Left ["Negative"]
        | n > 100   = Left ["Too large"]
        | otherwise = Right n
    
    combine :: Either [String] (Int, Int)
    combine =
        (,) <$> validate 5
            <*> validate (-2)
    




What Exactly Does f a Mean? Understanding Type Constructors in Haskell

  1. In Haskell, the notation f a looks like a function call, but it is not a value-level function.

  2. This syntax belongs to the type level, where f is a type constructor and a is a type that f takes as an input.

  3. A type constructor is like a "function on types":


  4. Type-Level Application
  5. Maybe Int   -- apply the constructor Maybe to Int
    [Char]      -- apply the list constructor [] to Char
    IO String   -- apply IO to String
    Either Int Bool -- apply Either to two types



  6. Type Constructors vs Value Functions
  7. f 3     -- value-level function call
    f a     -- type-level constructor application



  8. Kinds: Why f Must Have the Form * -> *
  9. class Functor f where
        fmap :: (a -> b) -> f a -> f b



  10. Concrete Examples
  11. f = Maybe
    f a = Maybe a   -- a new type
    f = []
    f a = [a]
    f = IO
    f a = IO a



  12. Partial Application of Type Constructors
  13. Either String Int  -- full application
    Either String      -- partial: kind becomes * -> *



  14. Why f a is NOT a Function



  15. Why Functor Requires a Type Constructor (* -> *)



  16. Summary





Monads in Haskell

  1. What Is a Monad?



  2. The Bind Operator (>>=)

  3. (>>=) :: m a -> (a -> m b) -> m b
    



  4. The (>>) Operator

  5. (>>) :: m a -> m b -> m b
    

    putStrLn "A" >> putStrLn "B"
    


  6. do-notation: Syntactic Sugar for Monads

  7. main = do
        putStrLn "Enter a number:"
        s  <- getLine
        let n = read s :: Int
        print (n * 2)
    

    main =
        putStrLn "Enter a number:" >>=
        \_ -> getLine >>=
        \s -> let n = read s in
              print (n * 2)
    



  8. Monad Laws (A lawful monad must satisfy)

  9. return a >>= f  ≡  f a
    
    m >>= return  ≡  m
    
    (m >>= f) >>= g  ≡  m >>= (\x -> f x >>= g)
    



  10. Common Monad Instances

  11. instance Monad Maybe where
        Nothing  >>= _ = Nothing
        Just x   >>= f = f x
    
    safeDiv a b =
        if b == 0 then Nothing else Just (a `div` b)
    
    calc = Just 10 >>= \x ->
           Just 2  >>= \y ->
           safeDiv x y
    

    instance Monad (Either e) where
        Left e  >>= _ = Left e
        Right x >>= f = f x
    

    instance Monad [] where
        xs >>= f = concat (map f xs)
    

    main = do
        name <- getLine
        putStrLn ("Hello " ++ name)
    


  12. Monads vs Applicatives vs Functors

  13. Concept Capabilities Signature
    Functor map a pure function over a structure fmap :: (a -> b) -> f a -> f b
    Applicative apply wrapped functions to wrapped values (<*>) :: f (a -> b) -> f a -> f b
    Monad perform computations where next step depends on previous results (>>=) :: m a -> (a -> m b) -> m b



  14. Examples of Monad Use Cases

  15. lookupUser id = ...
    lookupAddress user = ...
    lookupZip address = ...
    
    getZip id =
        lookupUser id >>= lookupAddress >>= lookupZip
    

    pairs = do
        x <- [1,2]
        y <- ['a','b']
        return (x, y)
    -- [(1,'a'),(1,'b'),(2,'a'),(2,'b')]
    

    parseInt s =
        if all isDigit s then Right (read s)
        else Left "not a number"
    
    sumInts a b = do
        x <- parseInt a
        y <- parseInt b
        return (x + y)
    

    main = do
        putStrLn "Enter a number:"
        s <- getLine
        print (read s + 1)
    


  16. Kleisli Composition

  17. (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
    

    f >=> g >=> h
    



Zippers in Haskell

  1. What Is a Zipper?



  2. An Intuitive Example: List Zipper

  3. data ListZipper a = ListZipper [a] a [a]
    
    ListZipper [2,1] 3 [4,5]
    

    goLeft (ListZipper (l:ls) x rs) = ListZipper ls l (x:rs)
    goRight (ListZipper ls x (r:rs)) = ListZipper (x:ls) r rs
    



  4. Zippers for Trees (The classical application)

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




  6. The Tree Zipper Context

  7. data Crumb a
        = LeftCrumb  a (Tree a)     -- went left, store value & right subtree
        | RightCrumb a (Tree a)     -- went right, store value & left subtree
    

    type Breadcrumbs a = [Crumb a]
    type Zipper a       = (Tree a, Breadcrumbs a)
    



  8. Navigating the Tree

  9. goLeft :: Zipper a -> Zipper a
    goLeft (Node x l r, bs) = (l, LeftCrumb x r : bs)
    

    goRight :: Zipper a -> Zipper a
    goRight (Node x l r, bs) = (r, RightCrumb x l : bs)
    

    goUp :: Zipper a -> Zipper a
    goUp (t, LeftCrumb x r : bs)  = (Node x t r, bs)
    goUp (t, RightCrumb x l : bs) = (Node x l t, bs)
    



  10. Editing with a Zipper

  11. modify :: (a -> a) -> Zipper a -> Zipper a
    modify f (Node x l r, bs) = (Node (f x) l r, bs)
    

    attach :: Tree a -> Zipper a -> Zipper a
    attach t (_, bs) = (t, bs)
    



  12. Building and Rebuilding the Entire Structure

  13. top :: Zipper a -> Zipper a
    top z@(_, []) = z
    top z         = top (goUp z)
    

    getTree :: Zipper a -> Tree a
    getTree = fst . top
    


  14. Example: Walking and Editing

  15. myTree =
        Node 1
            (Node 2 Empty Empty)
            (Node 3 Empty Empty)
    

    (tree1, ctx1) = goLeft (myTree, [])
    (tree2, ctx2) = modify (+1) (tree1, ctx1)
    resultTree    = getTree (tree2, ctx2)
    

    Node 1 (Node 3 Empty Empty) (Node 3 Empty Empty)
    


  16. Zippers Are Not Just for Trees



  17. Zipper Intuition Explained



  18. Performance




Haskell let ... in Expressions

  1. Intuition: What is let ... in?



  2. General Form and Scope

  3. let
        name1 = expr1
        name2 = expr2
        ...
    in bodyExpr
    
    outside :: Int
    outside =
        let a = 5
            b = 7
        in a * b
    
    -- Here, a and b are NOT visible anymore.
    -- outside == 35
    


  4. Multiple Bindings and Layout (Indentation)

  5. area :: Double
    area =
        let radius   = 10
            piApprox = 3.14159
        in piApprox * radius * radius
    


  6. Order of Bindings and Laziness

  7. weird :: (Int, Int)
    weird =
        let x = y + 1    -- "forward" reference
            y = 10
        in (x, y)
    -- weird == (11, 10)
    
    ones :: [Int]
    ones =
        let xs = 1 : xs   -- infinite list of 1s
        in xs
    


  8. let ... in vs. where


  9. hypotenuse :: Double -> Double -> Double
    hypotenuse a b =
        let a2 = a * a
            b2 = b * b
        in sqrt (a2 + b2)
    
    hypotenuse' :: Double -> Double -> Double
    hypotenuse' a b = sqrt (a2 + b2)
      where
        a2 = a * a
        b2 = b * b
    


  10. let Inside do-notation (No in)

  11. greet :: IO ()
    greet = do
        let name = "Haskell"
            msg  = "Hello, " ++ name
        putStrLn msg
    
    example :: IO ()
    example = do
        line <- getLine
        let trimmed = reverse (dropWhile (== ' ') (reverse line))
        putStrLn trimmed
    


  12. Pattern Bindings in let

  13. norm2 :: (Double, Double) -> Double
    norm2 v =
        let (x, y) = v
        in sqrt (x * x + y * y)
    

    printPair :: IO ()
    printPair = do
        let pair = (1, "one")
            (n, s) = pair
        putStrLn (show n ++ " - " ++ s)
    


  14. Shadowing and Common Pitfalls

  15. shadow :: Int -> Int
    shadow x =
        let x = x + 1
        in x
    



Haskell do-Notation

  1. Intuition: What is do-notation?



  2. What is a Monadic Bind (>>=)?

  3. (m >>= \x -> f x)
    


  4. Desugaring: How do-notation Expands


  5. foo :: Maybe Int
    foo = do
        x <- Just 3
        y <- Just 4
        return (x + y)
    
    foo :: Maybe Int
    foo =
        Just 3 >>= \x ->
        Just 4 >>= \y ->
        return (x + y)              -- Just (7)
    

    main = do
        putStrLn "Hello"
        putStrLn "World"
    
    main =
        putStrLn "Hello" >>
        putStrLn "World"
    


  6. <- Inside do-notation

  7. name <- action
    

    x <- 3       -- ❌ wrong: 3 is not a monadic action
    


  8. Pure Bindings in do: let

  9. main = do
        let x = 10
            y = 20
        print (x + y)
    


  10. Pattern Matching Inside do

  11. printPair :: IO ()
    printPair = do
        (x, y) <- return (1, "one")
        putStrLn (show x ++ ": " ++ y)
    


  12. Using do-notation with Other Monads (Not Just IO)

  13. half :: Int -> Maybe Int
    half x = if even x then Just (x `div` 2) else Nothing
    
    example :: Maybe Int
    example = do
        a <- half 20
        b <- half a
        return b
    -- example == Just 5
    


  14. Empty do Blocks and return
  15. example = do
        return 42    -- :: Maybe Int, IO Int, etc.
    


  16. Sequencing Without Bind: action1 >> action2

  17. main = do
        putStrLn "Hello"
        putStrLn "World"
    
    main =
        putStrLn "Hello" >>
        putStrLn "World"
    


  18. Common Pitfalls

    1. Forgetting that let does not use in inside do blocks.
    2. let x = 10 in print x    -- ❌ not allowed inside do
      
    3. Using <- on pure values.
    4. x <- 5    -- ❌ Wrong: 5 is not monadic
      let x = 5 -- ✔ Correct
      
    5. Mixing up do with imperative semantics.
    6. Under the hood, do is still purely functional.


Practical Real-World Code Examples of Functor, Applicative, and Monad

  1. Introduction:


  2. Functor: Apply a Pure Function Inside a Context


  3. 1. Maybe a as Functor
    -- Double a number inside Maybe
    example1 :: Maybe Int
    example1 = fmap (*2) (Just 10)
    
    -- Nothing stays Nothing
    example2 :: Maybe Int
    example2 = fmap (*2) Nothing
    
    example1 == Just 20
    example2 == Nothing
    

    2. List [] a / [a] as Functor
    example3 :: [Int]
    example3 = fmap (+1) [10, 20, 30]
    
    example3 == [11, 21, 31]
    

    3. IO a as Functor
    main1 :: IO ()
    main1 = do
        msg <- fmap (map toUpper) getLine
        putStrLn msg
    


  4. Applicative: Combine Independent Effects

  5. 1. Combining Maybe a values
    -- Add two Maybe numbers
    example4 :: Maybe Int
    example4 = pure (+) <*> Just 3 <*> Just 5
    
    example4 == Just 8
    
    example5 :: Maybe Int
    example5 = pure (+) <*> Just 3 <*> Nothing
    
    example5 == Nothing
    

    2. Applicative IO a — independent input
    main2 :: IO ()
    main2 = do
        pair <- (,) <$> getLine <*> getLine
        print pair
    

    3. Applicative Lists [] a / [a] (Cartesian product)
    example6 :: [Int]
    example6 = pure (+1) <*> [10,20,30]
    -- example6 = [(+1)] <*> [10,20,30]
    
    example6 == [11,21,31]
    
    example7 = (,) <$> [1,2] <*> ['a','b']
    
    example7 == [(1,'a'),(1,'b'),(2,'a'),(2,'b')]
    


  6. Monad: Dependent Sequencing


  7. 1. Maybe a as Monad — sequential failure
    safeDiv :: Int -> Int -> Maybe Int
    safeDiv _ 0 = Nothing
    safeDiv x y = Just (x `div` y)
    
    example8 :: Maybe Int
    example8 = do
        a <- safeDiv 100 2   -- Just 50
        b <- safeDiv a 5     -- Just 10
        return b
    
    example8 == Just 10
    

    2. [] a / [a] List Monad — branching / nondeterminism
    example9 :: [(Int, Int)]
    example9 = do
        x <- [1,2]
        y <- [10,20]
        return (x,y)
    
    example9 == [(1,10),(1,20),(2,10),(2,20)]
    

    3. IO a Monad — dependent input/output
    main3 :: IO ()
    main3 = do
        putStrLn "What is your name?"
        name <- getLine
        putStrLn ("Hello, " ++ name ++ "!")
    

    4. State Monad — threading state
    import Control.Monad.State
    
    tick :: State Int Int
    tick = do
        n <- get
        put (n + 1)
        return n
    
    example10 :: (Int, Int)
    example10 = runState (tick >> tick >> tick) 0
    
    tickTwice :: State Int (Int, Int)
    tickTwice = do
        a <- tick
        b <- tick
        return (a, b)
    
    example10 == (2,3)
    -- Explanation:
    -- tick 1: returns 0, state becomes 1
    -- tick 2: returns 1, state becomes 2
    -- tick 3: returns 2, state becomes 3
    


  8. Putting It All Together: A Practical Example

  9. readInt :: String -> Maybe Int
    readInt s =
        case reads s of
            [(n, "")] -> Just n
            _         -> Nothing
    
    example11 :: IO ()
    example11 = do
        putStrLn "Enter a number:"
        x <- readInt <$> getLine       -- Functor: apply inside IO
        putStrLn "Enter another:"
        y <- readInt <$> getLine       -- Functor again
    
        let result = pure (+) <*> x <*> y   -- Applicative: combine Maybe
        case result of
            Nothing   -> putStrLn "Invalid input"
            Just sum  -> putStrLn ("Sum: " ++ show sum)
    


Control Flow in Haskell

  1. Overview: Expressions, Not Statements



  2. if / then / else

  3. absVal :: Int -> Int
    absVal n =
        if n < 0
        then -n
        else n
    

    description :: Int -> String
    description n = "The number is " ++
        if n > 0 then "positive"
        else if n == 0 then "zero"
        else "negative"
    



  4. Guards: Multi-Way Branching for Functions

  5. sign :: Int -> Int
    sign n
        | n < 0     = -1
        | n == 0    = 0
        | otherwise = 1
    



  6. Pattern Matching and case Expressions


  7. head' :: [a] -> a
    head' (x:_) = x
    head' []    = error "empty list"
    


    describeMaybe :: Maybe Int -> String
    describeMaybe m =
        case m of
            Nothing  -> "No value"
            Just n   -> "Value: " ++ show n
    

    case expression of
        pattern1 -> result1
        pattern2 -> result2
        ...
    


  8. Boolean Operators and Short-Circuiting

  9. (&&) :: Bool -> Bool -> Bool
    (||) :: Bool -> Bool -> Bool
    not  :: Bool -> Bool
    
    safeDiv :: Int -> Int -> Maybe Int
    safeDiv _ 0 = Nothing
    safeDiv x y
        | y /= 0 && x `mod` y == 0 = Just (x `div` y)
        | otherwise               = Nothing
    


  10. let / where: Local Bindings for Structured Branches

  11. areaMessage :: Double -> Double -> String
    areaMessage w h =
        let area = w * h
        in  if area > 100
            then "Large area: " ++ show area
            else "Small area: " ++ show area
    

    greeting :: String -> String
    greeting name
        | long    = "Hello, distinguished " ++ name
        | short   = "Hi, " ++ name
        | otherwise = "Hey " ++ name
      where
        len   = length name
        long  = len > 10
        short = len < 4
    



  12. Recursion as "Loops"

  13. sumList :: [Int] -> Int
    sumList []     = 0
    sumList (x:xs) = x + sumList xs
    

    sumList' :: [Int] -> Int
    sumList' xs = go 0 xs
      where
        go acc []     = acc
        go acc (y:ys) = go (acc + y) ys
    



  14. Higher-Order Control: map, filter, fold, any, all

  15. map     :: (a -> b) -> [a] -> [b]
    filter  :: (a -> Bool) -> [a] -> [a]
    foldr   :: (a -> b -> b) -> b -> [a] -> b
    any     :: (a -> Bool) -> [a] -> Bool
    all     :: (a -> Bool) -> [a] -> Bool
    

    increaseAll :: [Int] -> [Int]
    increaseAll = map (+1)
    
    positives :: [Int] -> [Int]
    positives = filter (> 0)
    
    sumWithFold :: [Int] -> Int
    sumWithFold = foldr (+) 0
    
    hasNegative :: [Int] -> Bool
    hasNegative = any (< 0)
    
    allEven :: [Int] -> Bool
    allEven = all even
    



  16. Monadic Control Flow and do-Notation

  17. askName :: IO ()
    askName = do
        putStrLn "What is your name?"
        name <- getLine
        if null name
            then putStrLn "You didn't enter a name!"
            else putStrLn ("Hello, " ++ name ++ "!")
    
    safeRoot :: Double -> Maybe Double
    safeRoot x
        | x < 0     = Nothing
        | otherwise = Just (sqrt x)
    
    safeExpr :: Double -> Double -> Maybe Double
    safeExpr x y = do
        r1 <- safeRoot x
        r2 <- safeRoot y
        return (r1 + r2)
    



  18. Monadic Control Helpers: when, unless, forM, mapM

  19. when   :: Monad m => Bool -> m () -> m ()
    unless :: Monad m => Bool -> m () -> m ()
    
    forM   :: Monad m => [a] -> (a -> m b) -> m [b]
    mapM   :: Monad m => (a -> m b) -> [a] -> m [b]
    

    import Control.Monad (when, unless)
    
    askSecret :: IO ()
    askSecret = do
        putStrLn "Are you sure? (yes/no)"
        ans <- getLine
        when (ans == "yes") $
            putStrLn "The secret is: Haskell is cool!"
    
        unless (ans == "yes") $
            putStrLn "No secret for you."
    

    import Control.Monad (forM_)
    
    printLines :: [String] -> IO ()
    printLines xs = forM_ xs $ \line -> do
        putStrLn line
    




Introduction to Cabal (Haskell’s Build & Package Tool)

  1. What Is Cabal?


  2. Key Concepts



  3. Creating a New Cabal Project

  4. cabal init
    


  5. Understanding the .cabal File

  6. cabal-version:       3.8
    name:                myproject
    version:             0.1.0.0
    
    library
        exposed-modules:     MyLib
        hs-source-dirs:      src
        build-depends:       base >= 4.14 && < 5
        default-language:    Haskell2010
    
    executable myproject-exe
        main-is:             Main.hs
        hs-source-dirs:      app
        build-depends:       base, myproject
        default-language:    Haskell2010
    


  7. Building, Running, and Testing

  8. cabal build
    


    cabal run myproject-exe
    

    cabal test
    


    cabal repl
    


  9. Working with Dependencies

  10. build-depends: base, text >= 1.2
    

    cabal update
    


  11. Installing and Publishing

  12. cabal install
    

    cabal sdist
    

    cabal check
    



Grammar of data and class Declarations in Haskell

  1. Overview



  2. The Grammar of data Declarations

  3. data TypeName typeVars
        = Constructor1 fields
        | Constructor2 fields
        | ...
        deriving (Class1, Class2, ...)
    

    -- Positional
    Constructor t1 t2 t3
    
    -- Record syntax
    Constructor
        { field1 :: Type1
        , field2 :: Type2
        }
    

    data Shape
        = Circle Float
        | Rectangle Float Float
        | Triangle
    

    data Eq a => Weird a = W a
    

    deriving (Eq, Ord, Show)
    


  4. The Grammar of class Declarations

  5. class (Constraints) => ClassName typeVar where
        method1 :: type
        method2 :: type
        ...
    

    -- In the future, you can use (==) on any two values of the same type a,
    -- as long as that type a has an Eq instance.
    class Eq a where
        (==) :: a -> a -> Bool
    

    class Ord a where
        (<)  :: a -> a -> Bool
        (<=) :: a -> a -> Bool
        (>)  :: a -> a -> Bool
    

    class (Eq a, Show a) => MyClass a where
        method :: a -> String
    

    class Convert a b where
        convert :: a -> b
    

    class Eq a where
        (==) :: a -> a -> Bool
        (/=) :: a -> a -> Bool
        x /= y = not (x == y)     -- default implementation
    


  6. The Grammar of instance Declarations

  7. instance (Constraints) => ClassName typeArgs where
        method1 = ...
        method2 = ...
    

    instance Eq Person where
        (Person n1 a1) == (Person n2 a2) =
            n1 == n2 && a1 == a2
    

    -- Valid
    instance Ord (Maybe a) where ...
    
    -- INVALID (partial application)
    instance Ord Maybe where ...
    



Irrefutable Patterns in Haskell

  1. What Is an Irrefutable Pattern?


  2. Simple Irrefutable Patterns

  3. x :: Int
    x = 10          -- "x" is an irrefutable pattern
    
    y :: (Int, Int)
    y = (1, 2)      -- at top level, "y" is a variable pattern, always matches
    


  4. Pattern Bindings Are Lazy (Irrefutable) by Default

  5. example1 :: Int
    example1 =
        let (x, y) = undefined
        in 1
    
    example2 :: Int
    example2 =
        let (x, y) = undefined
        in x      -- "x" is demanded, pattern is forced, crash at runtime
    


  6. Explicit Lazy Patterns with ~

  7. f :: (Int, Int) -> Int
    f ~(x, y) = 1
    
    g :: (Int, Int) -> Int
    g (x, y) = 1
    


  8. Lazy Patterns in do-Notation

  9. exampleMaybe :: Maybe Int
    exampleMaybe = do
        Just x <- Just 3  -- OK
        return x
    
    exampleFail :: Maybe Int
    exampleFail = do
        Just x <- Nothing -- pattern match failure => Nothing
        return x
    
    exampleLazy :: Maybe (Maybe Int)
    exampleLazy = do
        ~(Just x) <- Nothing
        return (Just x)
    


  10. Irrefutable Patterns in where / let Blocks

  11. h :: Int
    h =
        let pair@(x, y) = undefined
        in 1       -- OK, pattern not forced
    
    h :: Int
    h =
        let ~(pair@(x, y)) = undefined
        in 1       -- OK, pattern not forced
    
    
    h :: Int
    h =
        let ~pair@(x, y) = undefined
        in 1       -- OK, pattern not forced
    
    k :: Int
    k =
        let pair@(x, y) = undefined
        in x       -- crash: forcing "x" forces the pattern
    


  12. Irrefutable vs Refutable in case and Function Arguments

  13. strictPair :: (Int, Int) -> Int
    strictPair (x, y) = x + y
    
    lazyPair :: (Int, Int) -> Int
    lazyPair ~(x, y) = 1
    
    caseExample :: Maybe Int -> Int
    caseExample m =
        case m of
            Just x -> x       -- refutable
            Nothing -> 0
    


  14. When Irrefutable Patterns Are Useful

  15. ones :: [Int]
    ones = xs
      where
        ~(x:xs) = 1 : xs   -- lazy pattern allows "xs" to refer to itself
    



Infix Operators, Fixity, and Associativity in Haskell

  1. What Is an Infix Operator?


  2. Why Fixity Matters


  3. Fixity Declaration Syntax



  4. Example: Declaring the Map Lookup Operators



  5. Associativity Explained



  6. Precedence Explained


  7. Custom Operators



  8. Fixity of Built-In Operators



  9. How to Read Fixity in Code



Haskell LANGUAGE Extensions

  1. What Are LANGUAGE Pragmas?


  2. Where Pragmas Can Appear



  3. Most Common Extensions (with concrete effects)


  4. How to Inspect Active Extensions?



GHC Non-LANGUAGE Pragmas (INLINE, UNPACK, SPECIALIZE, etc.)

  1. What Are Non-LANGUAGE Pragmas?


  2. INLINE and NOINLINE


  3. INLINABLE


  4. UNPACK and PACK



  5. BangPatterns vs UNPACK



  6. SPECIALIZE



  7. RULES — Rewrite Rules



  8. INLINEABLE vs SPECIALIZE in combination



  9. COMPLETE — Pattern Completeness Sets



  10. DEPRECATED / WARNING



  11. SOURCE pragma for imports



  12. INLINE Pragmas for Operators



The Beauty of Map Implementation in Haskell

  1. Introduction to Data.Map



  2. Why Balanced Binary Trees?



  3. Basic Map Structure



  4. Creating Maps



  5. The Beauty of Functional Lookup



  6. Insertion: Creating New Trees



  7. The Balance Function: Maintaining Tree Health



  8. Deletion: Elegant Recursion



  9. Map Operations: Functional Beauty



  10. Set Operations on Maps



  11. Conversion Functions



  12. Performance Characteristics



  13. Why This Implementation is Beautiful



  14. Practical Examples



  15. Advanced Patterns



  16. Comparison with Other Approaches



  17. Common Pitfalls and Best Practices