Lecture 06 Functions

Joseph Haugh

University of New Mexico

Review

Q: What is a type?

A: Collection of related values

Review

Q: What is a typeclass?

A: Collection of related types

Review

Q: What are typeclasses similar to in Java?

A: Interfaces

Review

Q: How are typeclasses more powerful?

A: Many typeclasses can be used to constrain 1 type argument

Review

Q: Can you name a typeclass we have seen so far?

A: Eq, Ord, Show, Read, Num, Integral, Fractional

Functions

  • The easiest function to define is a function defined from existing functions

  • Test if a given integer is even

    even :: Integral a => a -> Bool
    even n = n `mod` 2 == 0
  • Split a list at the nth element

    splitAt :: Int -> [a] -> ([a], [a])
    splitAt n xs = (take n xs, drop n xs)

Conditional Expressions

  • Haskell has if then else just like every other language
  • The difference is that it is an expression, not a statement
  • What does that mean?
  • It means you must always have an else!

Conditional Expressions

abs :: Int -> Int
abs n = if n >= 0 then n else -n

-- Can this be improved?
greaterThan10 :: Int -> Bool
greaterThan10 n = if n > 10 then True else False

Guards

  • Guards offer a syntactic sugar for conditional expressions
abs :: Int -> Int
abs n
  | n >= 0    = n
  | otherwise = -n

greaterThan10 :: Int -> Bool
greaterThan10 n
  | n > 10    = True
  | otherwise = False

Pattern Matching

  • Pattern matching is one of the most powerful features of Haskell
  • It allows you to destruct your arguments to see what pattern they match

Bool Pattern Matching

not :: Bool -> Bool
not True  = False
not False = True

(||) :: Bool -> Bool -> Bool
False || False = False
_     || _     = True

-- Does this work?
(||) :: Bool -> Bool -> Bool
_     || _     = True
False || False = False

(||) :: Bool -> Bool -> Bool
True  || _ = True
False || b = b

Tuple Pattern Matching

fst :: (a, b) -> a
fst (x, _) = x

snd :: (a, b) -> b
snd (_, y) = y

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

List Pattern Matching

null :: [a] -> Bool
null [] = True
null _  = False

inOrder :: Ord a => [a] -> Bool
inOrder []      = True
inOrder [_]     = True
inOrder [x,y]   = x <= y
inOrder [x,y,z] = x <= y <= z
-- This obviously needs recursion! We will come back to this.

firstIsOne :: [Int] -> Bool
firstIsOne (1:_) = True
firstIsOne _     = False

Building Lists

  • So far we have mostly seen list literals (e.g. [1,2,3])
  • However, most of the time lists will be built piece by piece
  • This is done using the cons operator (:)

Destructing A List

  • The list [1,2,3] can be destructed as follows:

        [1,2,3]
    =      { list notation}
        1 : [2,3]
    =      { list notation}
        1 : (2 : [3])
    =      { list notation}
        1 : (2 : (3 : []))

Lambda Expressions

  • An alternative way to construct function is using lambdas
  • Lambdas give a convenient way to define functions inline
  • Lambdas basic syntax is (\argument -> expression)
\x -> x + 1

Lambda Expressions

  • Ordinary functions can also be written in terms of lambdas

    add :: Int -> Int -> Int
    add x y = x + y
    
    add :: Int -> Int -> Int
    add = \x -> (\y -> x + y)
  • Lambdas can also use _ to ignore their arguments

    const :: a -> b -> a
    const x _ = x
    
    const :: a -> b -> a
    const = \x -> \_ -> x

Lambda Expressions

  • Lambdas find the most use in higher order functions

  • We haven’t seen a higher order function yet, but we will soon

  • One of the most used is the map function

  • map applies a function to every element of a list

    add1All :: [Int] -> [Int]
    add1All xs = map (\x -> x + 1) xs
    
    > add1All [1,2,3]
    [2,3,4]

Operator Sections

  • In that last example it seems tedious to create a lambda just to add 1

  • What if we could just give 1 to the + operator and then have it still take its other argument?

  • We can!

    add1All :: [Int] -> [Int]
    add1All xs = map (+1) xs
  • This is called an operator section

Operator Sections

  • (+1) is equivalent to \x -> x + 1
  • (1+) is equivalent to \x -> 1 + x

Operator Sections

subtract1All :: [Int] -> [Int]
subtract1All xs = map (-1) xs

> subtract1All [1,2,3]
[0,1,2]

subtractFrom1All :: [Int] -> [Int]
subtractFrom1All xs = map (1-) xs

> subtractFrom1All [1,2,3]
[0,-1,-2]

Exercises

  • Write a function fourth :: [a] -> a that returns the fourth element of a list using:
    • head and tail
    • list indexing (!!)
    • pattern matching

Exercises

  • Write a function halfAll :: [Int] -> [Int] that halves every element of a list using map with:
    • a separate function
    • a lambda
    • an operator section