Part 16

Recap, Quiz and Cheatsheet

Recap

Things you can use as patterns:

  • Int and Integer constants like (-1), 0, 1, 2, …
  • Bool values True and False
  • Char constants: 'a', 'b'
  • String constants: "abc", ""
  • Maybe constructors: Nothing, (Just x)
  • Either constructors: (Left x), (Right y)
  • The special _ pattern which means “anything, I don’t care”
  • Combinations of these patterns, like for example (Just 1)
  • We’ll learn about other patterns, for example lists, in the next chapters.

Places where you can use patterns:

  • Defining a function with equations:
f :: Bool -> Maybe Int -> Int
f False Nothing  = 1
f False _        = 2
f True  (Just i) = i
f True  Nothing  = 0
  • In the case of expression:
case number of 0 -> "zero"
                1 -> "one"
                _ -> "not zero or one"

The only thing you really need pattern matching for is getting the value inside a Just, Left or Right constructor. Here are two more examples of this:

-- getElement (Just i) gets the ith element (counting from zero) of a list, getElement Nothing gets the last element
getElement :: Maybe Int -> [a] -> a
getElement (Just i) xs = xs !! i
getElement Nothing xs = last xs

Prelude> getElement Nothing "hurray!"
'!'
Prelude> getElement (Just 3) [5,6,7,8,9]
8

direction :: Either Int Int -> String
direction (Left i) = "you should go left " ++ show i ++ " meters!"
direction (Right i) = "you should go right " ++ show i ++ " meters!"

Prelude> direction (Left 3)
"you should go left 3 meters!"
Prelude> direction (Right 5)
"you should go right 5 meters!"

Other uses (that we’ve seen so far!) of pattern matching can also be accomplished with the == operator. However, things like x==Nothing won’t work in all cases. We’ll find out why when we talk about type classes in a later chapter.

Quiz

How many values does f x = [x,x] return?

  1. Zero
  2. One
  3. Two

Why does the expression Nothing 1 cause a type error?

  1. Because Nothing takes no arguments
  2. Because Nothing returns nothing
  3. Because Nothing is a constructor

What is the type of the function f x y = if x && y then Right x else Left "foo"?

  1. Bool -> Bool -> Either Bool String
  2. String -> String -> Either String String
  3. Bool -> Bool -> Either String Bool

Which of the following functions could have the type Bool -> Int -> [Bool]

  1. f x y = [0, y]
  2. f x y = [x, True]
  3. f x y = [y, True]

What is the type of this function? justBoth a b = [Just a, Just b]

  1. a -> b -> [Maybe a, Maybe b]
  2. a -> a -> [Just a]
  3. a -> b -> [Maybe a]
  4. a -> a -> [Maybe a]

Cheatsheet

Another cheatsheet, credits to our TA Daan Wichmann

import Data.List  -- Importing module

-- Helper functions (e.g. when we want to accumulate something in recursion i.e. we need helper variables)

-- Function: calculating fibonnaci numbers efficiently
efficientFib :: Integer -> Integer
efficientFib n = efficientFib' 0 1 n  -- Note the comma! This is a different function: a helper function

-- Our helper function
efficientFib' :: Integer -> Integer -> Integer -> Integer
efficientFib' a b 1 = b
efficientFib' a b n = efficientFib' b (a + b) (n - 1)

-- Guards
guessMyAge :: Int -> String
guessMyAge guess
    | guess < 18 = "Too low!"
    | guess > 22 = "Too high!"
    | otherwise = "Close!"

-- Lists: lists are homogeneous is Haskell
tas :: [String]  -- Lists are parameterized types, 'String' is a type parameter here.
tas = ["Daan", "Damai", "Ella", "Mateusz", "Paula"]

-- List operations
-- head :: [a] -> a            -- returns the first element
-- last :: [a] -> a            -- returns the last element
-- tail :: [a] -> [a]          -- returns everything except the first element
-- init :: [a] -> [a]          -- returns everything except the last element
-- take :: Int -> [a] -> [a]   -- returns the n first elements
-- drop :: Int -> [a] -> [a]   -- returns everything except the n first elements
-- (++) :: [a] -> [a] -> [a]   -- lists are catenated with the ++ operator
-- (!!) :: [a] -> Int -> a     -- lists are indexed with the !! operator (starts at 0)
-- reverse :: [a] -> [a]       -- reverse a list
-- null :: [a] -> Bool         -- is this list empty?
-- length :: [a] -> Int        -- the length of a list
-- sort :: [a] -> [a]          -- from the Data.List module

numberOfTAs :: Int
numberOfTAs = length tas

-- Ranges
digits :: [Int]
digits = [1..9]  -- 1, 2, 3, 4, 5, 6, 7, 8, 9

evens :: [Int]
evens = [2,4..10]  -- 2, 4, 6, 8, 10

countingDown :: [Int]
countingDown = [10,9..1]  -- 10, 9, 8, 7, 6, 5, 4, 3, 2, 1

infiniteRange :: [Int]
infiniteRange = [1,2..]

tenMultiplesOf2 :: [Int]
tenMultiplesOf2 = take 10 [2,4..]  -- Possible because Haskell = lazy

cycleIntList :: [Int] -> Int -> [Int]
cycleIntList lst n = take n (cycle lst)

repeatInt :: Int -> Int -> [Int]  -- Equivalent: replicate
repeatInt int n = take n (repeat int)


-- 'a' is a type variable
-- customHead is polymorphic
customHead :: [a] -> a
customHead lst = lst !! 0


-- Maybe
job :: String -> Maybe String
job "Bryan" = Just "Lecturer"
job "Emma" = Just "Lecturer"
job "Daan" = Just "TA"
job "Damai" = Just "TA"
job "Ella" = Just "TA"
job "Mateusz" = Just "TA"
job "Paula" = Just "TA"
job _ = Nothing

personel :: Maybe String -> [String]
personel (Just "TA") = ["Daan", "Damai", "Ella", "Mateusz", "Paula"]
personel (Just "Lecturer") = ["Bryan", "Emma"]
personel Nothing = ["Student A", "Student B"]

-- Either
readInt :: String -> Either String Int
readInt "0" = Right 0
readInt "1" = Right 1
readInt s = Left ("Unsupported string: " ++ s)

-- Case-of

parseCountry :: String -> Maybe String
parseCountry "FI" = Just "Finland"
parseCountry "SE" = Just "Sweden"
parseCountry _ = Nothing

flyTo :: String -> String
flyTo countryCode =
    case parseCountry countryCode of
        Just country -> "You're flying to " ++ country
        Nothing -> "You're not flying anywhere"

-- Note: case-of expressions can always be rewritten to helper functions!
-- We can use case-of when we want to match against function outputs.
-- When we want to use local helper function in all cases.
-- Cleaner
You have reached the end of this section!

You can check your current points from the blue blob in the bottom-right corner of the page.