Tuples and Lists Lecture 3, Programmeringsteknik del A.

50
Tuples and Lists Lecture 3, Programmeringsteknik del A.

Transcript of Tuples and Lists Lecture 3, Programmeringsteknik del A.

Tuples and Lists

Lecture 3,

Programmeringsteknik del A.

Tuples

A tuple is a value made up of several other values, its components.

Examples:

•A point in the plane (x,y)

•A point in space (x,y,z)

•A purchase (”Dagens Lunch”, 55)

•The null tuple ()

Round bracketsand commas.

Tuple Types

A tuple type specifies the type of each component.

Examples:

(1,2) :: (Int, Int)

(1.5, 2.25) :: (Float, Float)

(”Dagens Lunch”, 55) :: (String, Int)

() :: ()

Type Definitions

We can give names to types with a type definition:

type Purchase = (String, Int)

Now Purchase and (String, Int) are interchangeable:

dagens :: Purchase

dagens = (”Dagens Lunch”, 55)

All types start with a capital letter.

Pattern Matching

Functions on tuples can be defined by pattern matching:

name :: Purchase -> String

name (s, i) = s

price :: Purchase -> Int

price (s, i) = i

A pattern which must matchthe actual argument.

Standard Selector Functions

fst (x, y) = x

snd (x, y) = y

But we cannot define:

select 1 (x, y) = x

select 2 (x, y) = y

The type of a function’s result is not allowed to depend on the values of the arguments.

What would the typeof the result be?

Lists

A list is also a value made up of other values, its elements.

Examples:

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

[True, False, True] :: [Bool]

[] :: [Float]

[(”Dagens Lunch”, 55)] :: [Purchase]

Tuples vs. Lists

A tuple consists of a fixed number of components, of various types.

Useful, but not much to know.

A list consists of any number of elements, all of the same type.

Ubiquitous! Supported by a rich set of standard functions and constructions.

Lists Can Make Programs Simpler!

Whenever there is a sequence of values, consider using a list.

Lists for Counting

We often need to count:

[1..10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[1,3..10] = [1, 3, 5, 7, 9]

Example:

fac :: Int -> Int

fac n = product [1..n]

Standard function tomultiply together list elements.

List Comprehensions

We often do the same thing to every element of a list:

Example:

doubles :: [Int] -> [Int]

doubles xs = [2 * x | x <- xs]

doubles [1..3] [2, 4, 6]

For each elementx of xs...

Add 2*x to thelist produced.

Summing Squares with Lists

n

[1, 2, 3, …, n]

[1, 4, 9, …, n^2]

1 + 4 + 9 + … + n^2

sumsq :: Int -> Int

sumsq n = sum [i^2 | i <- [1..n]]

Add up the elements of a list.

Filtering Lists

A list comprehension can include a condition which elements must satisfy.

Example:

factors :: Int -> [Int]

factors n = [i | i <- [2..n], n `mod` i == 0]

factors 12 [2, 3, 4, 6, 12]

Include only those iwhich pass this test.

Using factors

Counting the number of factors…

numFactors :: Int -> Int

numFactors n = length (factors n)

Testing for a prime number…

isPrime :: Int -> Bool

isPrime n = factors n == [n]

The number of elementsin a list.

Designing List Comprehensions

Ask yourself: Do I want to process a sequence of elements in turn?

If so, use a list comprehension!

[ | <- ]

Start by writing downa framework with gaps

to be filled in.

Designing List Comprehensions

Ask yourself: What is the list whose elements I want to process?

[ | <- [2..n] ]

Write it in the gap after the left arrow.

Designing List Comprehensions

Ask yourself: What will I call each element?

[ | i <- [2..n] ]

Fill the name in tothe left of the arrow.

Designing List Comprehensions

Ask yourself: Do I want to process every element, or make a selection from them?

[ | i <- [2..n], n `mod` i == 0]

Write a comma anda condition at the endof the comprehension.

Designing List Comprehensions

Ask yourself: What values do I want in the result?

[ i | i <- [2..n], n `mod` i == 0]

Write an expressionbefore the bar.

Lists vs. Recursion?

Even problems which do not mention lists can often be solved easily by using lists internally.

Haskell’s powerful list constructions often offer a simpler alternative to using recursion.

But not always! Recursion is a powerful and general tool -- therefore harder to use than special purpose tools, when they are applicable.

Example: A Library Database

Computerise the librarian’s card file:

John HughesborrowedThe Craft of Functional Programming

Simon ThompsonborrowedScience Goes Boink!

Representing a Loan Card

What is the information on a loan card?

John HughesborrowedThe Craft of Functional Programming

Borrower’sname.

Book title.

type Borrower = String

type Book = String

type Card = (Borrower, Book)

Representing the Card File

What is the contents of the card file?

-- a sequence of loan cards!

type Database = [Card]

example :: Database

example = [ (”John Hughes”, ”The Craft of Functional Programming”),

(”Simon Thompson”, ”Science Goes Boink!”) ]

Querying the Database

What information would we wish to extract?

books :: Database -> Borrower -> [Book]

borrowers :: Database -> Book -> [Borrower]

borrowed :: Database -> Book -> Bool

numBorrowed :: Database -> Borrower -> Int

Which Books Have I Borrowed?

books example ”John Hughes” =

[”The Craft of Functional Programming”]

books example ”Mary Sheeran” = []

books db person =

[book | (borrower, book) <- db, borrower == person]

No booksborrowed.

Pattern matching again.

Quiz

Define:

numBorrowed :: Database -> Borrower -> Int

Quiz

Define:

numBorrowed :: Database -> Borrower -> Int

numBorrowed db person = length (books db person)

Updating the Database

Making and returning loans changes the contents of the database.

makeLoan :: Database -> Borrower -> Book -> Database

returnLoan :: Database -> Book -> Database

These functions use theinformation in the

database beforehand...

… to compute theinformation in the

database afterwards.

Making a Loan

makeLoan :: Database -> Borrower -> Book -> Database

makeLoan db borrower book = [(borrower, book)] ++ db

Make a new card.

Returning a Loan

returnLoan :: Database -> Book -> Database

returnLoan db book =

[(borrower, book’) | (borrower, book’) <- db,

book’ /= book]

The Role of Lists

Lists offer a natural way to model real world information -- sequences are everywhere!

Lists are easy to manipulate thanks to Haskell’s support: a good first choice of data structure.

Lists are not always efficient: candidates for replacement by faster structures later in program development.

Some Standard List Functions

Haskell provides many standard functions to manipulate lists. Let’s look at a few.

But first:

What is the type of length?

Polymorphic Types

length :: [Int] -> Int

length :: [Float] -> Int

length :: [Card] -> Int

For any type t,

length :: [t] -> Int

length has many types!It is polymorphic.

That is why it is useful.

A type variable,which may stand for

any type.

Taking and Dropping

•take n xs the first n elements of xs,

•drop n xs all but the first n elements.

Examples:

take 3 (factors 12) [2, 3, 4]

drop 3 (factors 12) [6, 12]

Quiz

take and drop have the same (polymorphic) type. What is it?

Quiz

take and drop have the same (polymorphic) type. What is it?

take, drop :: Int -> [a] -> [a]

Examples:

Int -> [Float] -> [Float]

Int -> [String] -> [String]

Not Int -> [Float] -> [String]

A must stand for thesame type everywhere.

The Zipper

Often we want to combine corresponding elements of two lists:

zip [ ”John” , ”Simon”, ”Mary” ]

[ ”Welsh”, ”English”, ”Irish” ]

[ (”John”,”Welsh”), (”Simon”,”English”), (”Mary”,”Irish”)]

The type of zip

zip :: [a] -> [b] -> [(a, b)]

Example:

zip [1, 2, 3] [”a”, ”b”, ”c”]

[(1,”a”), (2,”b”), (3,”c”)]

Here zip :: [Int] -> [String] -> [(Int, String)]

Example: The Position of x in xs

position :: a -> [a] -> Int

Example: position ”b” [”a”, ”b”, ”c”] 2

Idea: Mark every element with its position, and search for the one we want.

Marking Elements with Positions

[”a”, ”b”, ”c”] [(”a”,1), (”b”,2), (”c”,3)]

zip [”a”, ”b”, ”c”]

[ 1, 2, 3 ]

[(”a”,1), (”b”,2), (”c”,3)]

Use zip xs [1..length xs]

Searching for the Right Element

Select the positions where the element we’re searching for appears:

positions x xs = [pos | (x’,pos) <- zip xs [1..length xs],

x’ == x]

positions ”b” [”a”, ”b”, ”c”] [2]A list. Wewant justa number.

The Complete Position Function

position :: a -> [a] -> Int

position x xs = head [pos | (x’,pos) <- zip xs [1..length xs],

x’ == x]

Select the firstelement from thelist of positions.

Example: Calculate Path Lengths

How long is the path?

Representing a Point

type Point = (Float, Float)

distance :: Point -> Point -> Float

distance (x, y) (x’, y’) = sqrt ((x-x’)^2 + (y-y’)^2)

x- and y-coordinates.

Representing a Path

P

Q

R

type Path = [Point]

examplePath = [p, q, r, s]

path length = distance p q + distance q r + distance r s

S

Two Useful Functions

•init xs -- all but the last element of xs,

•tail xs -- all but the first element of xs.

init [p, q, r, s] [p, q, r]

tail [p, q, r, s] [q, r, s]

zip … [(p,q), (q,r), (r,s)]

The pathLength Function

pathLength :: Path -> Float

pathLength xs = sum [distance p q

| (p,q) <- zip (init xs) (tail xs)]

Example:

pathLength [p, q, r, s]

distance p q + distance q r + distance r s

Rule of Thumb

Question: Do I want to go through the elements of two lists together?

Answer: Use zip!

Lessons

Lists model any kind of sequence in the real world.

Lists can express many kinds of repeated computation in programs.

Special constructions and a rich set of polymorphic standard functions let us manipulate lists very easily indeed.

Look for opportunities to use them!

Reading

This lecture is largely based on Chapter 5 of the text book, up to section 5.7. Read this, and try exercises 5.11, 5.12, 5.13, and 5.14.

Section 5.8 summarises a number of standard functions on lists. Knowing these functions will make list programming much easier for you.