CSci 450/503: Programming Languages

List Programming

H. Conrad Cunningham

18 September 2017

Acknowledgements: These slides accompany Chapter 4 “List Programming” from “Introduction to Functional Programming Using Haskell”.

Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of September 2017 is a recent version of Firefox from Mozilla.

List Programming

Lecture Goals

Haskell Data Structures

Immutable:

not subject to change as program executes

Lists

List Syntactic Sugar

Syntactic sugar:

notation that simplifies expression, but adds no new functionality

List Operations

String

Polymorphic Lists

Polymorphism:

property of having “many shapes”

Kinds of Polymorphism (1)

  1. Ad hoc polymorphism, same function name denotes different implementations depending on use

    • Overloading, compiler determines which to invoke, early binding

      E.g., + in Java, Haskell type classes

    • Subtyping, runtime searches hierarchy of types, late binding

      Called just polymorphism in Java, does not exist in Haskell

Kinds of Polymorphism (2)

  1. Parametric polymorphism, same implementation used for different types

    Called generics in Java, Haskell just polymorphism

Programming with List Patterns

Add List of Int (1)

Add List of Int (2)

    sum' :: [Int] -> Int  -- sum in Prelude 
    sum' []     = 0           -- nil list 
    sum' (x:xs) = x + sum' xs -- non-nil list 

Add List of Int (3)

Exercise: Write a variant of sum' that uses a tail recursive auxiliary function.

Multiply List of Integer (1)

    product' :: [Integer] -> Integer  -- product in Prelude
    product' []     = 1               -- nil list
    product' (0:_)  = 0               -- 0 at head
    product' (x:xs) = x * product' xs -- non-nil, non-zero

Multiply List of Integer (2)

    product' :: [Integer] -> Integer  -- product in Prelude
    product' []     = 1               -- nil list
    product' (0:_)  = 0               -- 0 head, don't care
    product' (x:xs) = x * product' xs -- non-nil, non-zero

Comparison of sum' and product'

Length of List

    length' :: [a] -> Int  -- length in Prelude
    length' []     = 0              -- nil list
    length' (_:xs) = 1 + length' xs -- non-nil list

Adjacent Duplicates (1)

Adjacent Duplicates (2)

Adjacent Duplicates (3)

How can we make work for polymorphic list?

More List Patterns (1)

Pattern Argument Succeeds? Bindings
1 1 yes none
x 1 yes x \leftarrow 1
(x:y) [1,2] yes x \leftarrow 1, y \leftarrow [2]
(x:y) [[1,2]] yes x \leftarrow [1,2], y \leftarrow []
(x:y) ["olemiss"] yes x \leftarrow "olemiss", y \leftarrow []
(x:y) "olemiss" yes x \leftarrow ’o’, y \leftarrow "lemiss"

More List Patterns (2)

Pattern Argument Succeeds? Bindings
(1:x) [1,2] yes x \leftarrow [2]
(1:x) [2,2] no none
(x:_:_:y) [1,2,3,4,5,6] yes x \leftarrow 1, y \leftarrow [4,5,6]
[] [] yes none
[x] ["Cy"] yes x \leftarrow "Cy"
[1,x] [1,2] yes x \leftarrow 2
[x,y] [1] no none
(x,y) (1,2) yes x \leftarrow 1, y \leftarrow 2

Data Sharing

    xs = [1,2,3]
    ys = 0:xs 
    zs = tail xs 
Data Sharing in Linked Lists

Data Sharing in Linked Lists

Drop Elements from List (1)

Drop Elements from List (2)

    drop' :: Int -> [a] -> [a]  -- drop in Prelude
    drop' n xs | n <= 0 = xs 
    drop' _ []          = []
    drop' n (_:xs)      = drop' (n-1) xs 

Take Elements from List (1)

Take Elements from List (2)

Infix Operations (1)

Binary operation:

function of type t1 -> t2 -> t3

Infix Operations (2)

Common Infix Operations

    infixr 8 ^                     -- exponentiation
    infixl 7 *                     -- multiplication
    infix  7 /                     -- division
    infixl 6 +, -                  -- addition, subtraction
    infixr 5 :                     -- cons
    infix  4 ==, /=, <, <=, >=, >  -- relational comparisons
    infixr 3 &&                    -- Boolean AND
    infixr 2 ||                    -- Boolean OR 

Function application has precdence of 10

Appending Lists: ++

    infixr 5 ++
    
    (++) :: [a] -> [a] -> [a]   -- in Prelude 
    [] ++ xs     = xs           -- nil left operand 
    (x:xs) ++ ys = x:(xs ++ ys) -- non-nil left operand 

Properties of ++ (1)

Associativity if ++:

For any finite lists xs, ys, and zs, xs ++ (ys ++ zs) == (xs ++ ys) ++ zs

Identity for ++:

For any finite list xs, [] ++ xs = xs = xs ++ []

Properties of ++ (2)

Element Selection: !!

    infixl 9 !!

    (!!) :: [a] -> Int -> a 
    xs     !! n | n < 0 = error "!! negative index"
    []     !! _         = error "!! index too large"
    (x:_)  !! 0         = x 
    (_:xs) !! n         = xs !! (n-1) 

Reversing a List: rev (1)

    rev :: [a] -> [a]
    rev []     = []            -- nil argument
    rev (x:xs) = rev xs ++ [x] -- non-nil argument

Reversing a List: rev (2)

Distribution:

For any finite lists xs and ys, rev (xs ++ ys) = rev ys ++ rev xs

Inverse:

For any finite list xs, rev (rev xs) = xs

For any finite lists xs and ys and natural numbers n,

    take n (rev xs)  = rev (drop (length xs - n) xs)

Tail recursive reverse

    reverse' :: [a] -> [a]n -- reverse in Prelude 
    reverse' xs = rev xs []
                  where rev []     ys = ys 
                        rev (x:xs) ys = rev xs (x:ys) 

Other Useful List Functions

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

    zip' :: [a] -> [b] -> [(a,b)]   -- zip in Prelude
    zip' (x:xs) (y:ys) = (x,y) : zip' xs ys -- zip.1
    zip' _      _      = []                 -- zip.1

    unzip' :: [(a,b)] -> ([a],[b])  -- unzip in Prelude
    unzip' []         = ([],[])
    unzip' ((x,y):ps) = (x:xs, y:ys)
                        where (xs,ys) = unzip' ps

Insertion Sort

Ascending:

Every element is <= all of its successors

  • similar for descending, increasing, decreasing
Idea:

To sort x:xs, sort tail xs, then insert x at correct position

Empty list is sorted

Insertion Sort of Int

    isort :: [Int] -> [Int]
    isort []     = []
    isort (x:xs) = insert x (isort xs)

    insert :: Int -> [Int] -> [Int]
    insert x []     = [x]
    insert x xs@(y:ys)     -- xs alias of (y:xs)
        | x <= y    = (x:xs)
        | otherwise = y : (insert x ys)

Polymorphic Insertion Sort

Polymorphic list, element constrained to class Ord

    isort' :: Ord a => [a] -> [a]
    isort' []     = []
    isort' (x:xs) = insert' x (isort' xs)

    insert' :: Ord a => a -> [a] -> [a]
    insert' x []    = [x]
    insert' x xs@(y:ys)     -- xs alias of (y:xs)
        | x <= y    = (x:xs)
        | otherwise = y : (insert' x ys)

Key Ideas

Code

The Haskell code for this section is in file Mod04Lists.hs.