<<

Intro duction to Lecture

Intro duction to

Functional Programming

John Harrison

University of Cambridge

Lecture

Eective ML

Topics covered

 Using standard combinators

 Abstract typ es

 Tail and accumulators

 Forcing evaluation

 Minimizing consing

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Using standard combinators

It often turns out that a few combinators are very

useful we can implement practically anything by

plugging them together esp ecially given higher

order functions

itlist function For example the

itlist f x x x b

n

f x f x f x    f x b

n

can often b e used to avoid explicit recursive

denitions over lists We dene it as

fun itlist f b b

itlist f ht b

f h itlist f t b

val itlist fn a b b

a list b b

Functions of this sort are often built in to

functional langauges and sometimes called

something like fold

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Itlist examples

For example here is a function to add up all the

elements of a list

fun sum l

itlist fn x fn sum x sum

l

val sum fn int list int

sum

val it int

sum

val it int

If we want to multiply the elements instead we

change it to

fun prod l

itlist fn x fn prod x prod

l

val prod fn int list int

prod

val it int

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Itlist examples

Here is a ltering function

fun filter p l itlist

fn x fn s

if p x then xs else s l

and here are some logical op erations over lists

fun forall p l itlist

fn h fn a ph andalso a

l true

fun exists p l itlist

fn h fn a ph orelse a

l false

and some old favourites

fun length l

itlist fn x fn s s l

fun append l m

itlist fn h fn t ht l m

fun map f l itlist

fn x fn s f xs l

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Itlist examples

We can implement set op erations quite directly

using these combinators as building blo cks

fun mem x l

exists fn y y x l

fun insert x l

if mem x l then l else xl

fun union l l

itlist insert l l

fun setify l

union l

fun Union l

itlist union l

fun intersect l l

filter fn x mem x l l

fun subtract l l

filter fn x not mem x l l

fun subset l l

forall fn t mem t l l

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Abstract typ es

An abstract typ e starts with an ordinary

recursive typ e and then imp oses restrictions on

how the ob jects of the typ e can b e manipulated

Essentially users can only interact by a particular

interface of functions and values

The advantage is that users cannot rely on any

other internal details of the typ e

This improves mo dularity eg it is easy to

replace the implementation of the abstract typ e

with a new b etter smaller faster not patented

one without requiring any changes to user

co de

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Example sets

Here is an abstract typ e for integer sets

abstype set Set of int list with

val empty Set

fun setinsert a Set s

Set insert a s

fun setunion Set s Set t

Set union s t

fun setintersect Set s Set t

Set intersect s t

fun setsubset Set s Set t

subset s t

end

Users cant access the internal representation

lists which is only done via the interface

functions

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Example sets

Many of the op erations are much more ecient if

we keep the lists sorted into numerical order For

example

fun sunion

sunion l l

sunion l l

sunion ht ht

if h h then

hsunion t ht

else if h h then

hsunion ht t

else hsunion t t

val sunion fn int list

int list int list

We can change the internal representation to use

sorted lists or balanced trees or arrays and

no changes are needed to co de using the abstract

typ e

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Storing lo cal variables

Recall our denition of the factorial

fun fact n if n then

else n factn

A call to fact causes another call to fact

and b eyond but the computer needs to save the

in order to do the nal multiplication old value

Therefore the lo cal variables of a function in this

n cannot b e stored in a xed place b ecause case

each instance of the function needs its own copy

Instead each instance of the function is allo cated

a frame on a stack

This technique is similar in ML to most other

languages that supp ort recursion including

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

The stack

Here is an imaginary snapshot of the stack during

fact the evaluation of the innermost call of

n

n

n

n

n

n

n

-

SP

Note that we use ab out n words of storage when

n nested recursive calls In many there are

situations this is very wasteful

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

A tail recursive version

Now by contrast consider the following

implementation of the factorial function

fun tfact x n

if n then x

else tfact x n n

val tfact fn int int int

fun fact n tfact n

val fact fn int int

fact

val it int

The recursive call is the whole expression it do es

not o ccur as a prop er sub expression of some other

expression involving values of variables

Such a call is said to b e a tail cal l b ecause it is

the very last thing the calling function do es

A function where all recursive calls are tail calls is

said to b e tail recursive

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Why tail recursion

If a function is tail recursive the is

clever enough to realize that the same area of

storage can b e used for the lo cal variables of each

instance

We avoid using all that stack

x of the tfact function The additional argument

is called an accumulator b ecause it accumulates

the result as the recursive calls stack up and is

then returned at the end

Working in this way rather than mo difying the

return value on the way back up is a common

way of making functions tail recursive

In a sense a tail recursive implementation using

accumulators corresp onds to an iterative version

using assignments and whilelo ops

The only dierence is that we pass the state

around explicitly

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Forcing evaluation

Recall that ML do es not evaluate inside lamb das

Therefore it sometimes pays to pull expressions

outside a lamb da when they do not dep end on the

value of the b ound variable

For example we might co de the ecient factorial

tfact lo cal by making

fun fact n

let fun tfact x n

if n then x

else tfact x n n

in tfact n

end

However the binding of the recursive function to

tfact do es not get evaluated until fact sees its

arguments

Moreover it gets reevaluated each time even

n though it do esnt dep end on

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Forcing evaluation

A b etter co ding is as follows

val fact

let fun tfact x n

if n then x

else tfact x n n

in tfact

end

In cases where the sub expression involves much

more evaluation the dierence can b e sp ectacular

Most do not do such optimizations

automatically

However it falls under the general heading of

partial evaluation a big research eld

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Forcing evaluation

An alternative co ding is to use local

A b etter co ding is as follows

local fun tfact x n

if n then x

else tfact x n n

in fun fact n tfact n

end

val fact fn int int

The lo cal declaration is invisible outside the b o dy

fact of

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Minimizing consing

The space used by typ e constructors cells

is not allo cated and deallo cated in such as

straightforward way as stack space

In general it is dicult to work out when a

certain cons cell is in use and when it is available

for recycling For example in

val l in tl l

the cons cell can b e reused immediately However

l is passed to other functions it is imp ossible if

to decide at compiletime when the cons cell is no

longer needed

Therefore space in functional languages has to b e

reclaimed by analyzing memory p erio dically and

deciding which bits are needed The remainder is

then reclaimed This pro cess is known as garbage

col lection

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Minimizing consing

We can often make programs more space and

time ecient by reducing consing One simple

trick is to reduce the usage of append By lo oking

at the denition

fun append l l

append ht l happend t l

val append fn

a list a list a list

we can see that it generates n cons cells where n

is the length of the rst argument For example

this implementation of reversal

fun rev

rev ht append rev t h

val rev fn a list a list

is very inecient generating ab out n cons

n is the length of the list cells where

John Harrison University of Cambridge January

Intro duction to Functional Programming Lecture

Minimizing consing

A far b etter version is

local fun reverse acc acc

reverse ht acc

reverse t hacc

in fun rev l reverse l

end

val rev fn a list a list

This only generates n cons cells and has the

additional merit of b eing tail recursive so we save

stack space

One can also avoid consing in patternmatching

as eg instead of rebuilding a cons cell by using

fn

ht if h then t else ht

using

fn

l as ht if h then t else l

John Harrison University of Cambridge January