57
Functional languages and how to implement them Karl-Filip Faxén KTH/IMIT/LECS

Functional languages and how to implement them

Embed Size (px)

DESCRIPTION

Functional languages and how to implement them. Karl-Filip Faxén KTH/IMIT/LECS. Functional programming. A functional program computes a result from a set of arguments compute a target program from a source program compute a bitmap image from a scene description - PowerPoint PPT Presentation

Citation preview

Page 1: Functional languages and how to implement them

Functional languages and how to implement them

Karl-Filip FaxénKTH/IMIT/LECS

Page 2: Functional languages and how to implement them

Functional programming

A functional program computes a result from a set of argumentscompute a target program from a source programcompute a bitmap image from a scene description

A function (subprogram) is a function (mapping)computes a result from arguments withno side effects!

Well known functional languages includeStandard ML (not purely functional)Haskell (purely functional)

Page 3: Functional languages and how to implement them

Functional languages

Garbage collection Polymorphic typing

Catches all type errors at compile timeTypes are inferred and need not be givenPolymorphism allows generic functions to be

written

First class functionsAllows for higher order functions

Eager (strict) or lazy (nonstrict) evaluationStandard ML is strictHaskell is nonstrict

Page 4: Functional languages and how to implement them

Strict or nonstrict?

let z = x/y in if y == 0 then 1 else z

What happens if y=0?

Page 5: Functional languages and how to implement them

Strict or nonstrict?

let z = x/y in if y == 0 then 1 else z

What happens if y=0? - In a strict language (SML): a run-time error - In a lazy language (Haskell): return the value 1

Page 6: Functional languages and how to implement them

Strict or nonstrict?

if y == 0 then 1 else x/y

What happens if y=0?

Page 7: Functional languages and how to implement them

Strict or nonstrict?

if y == 0 then 1 else x/y

What happens if y=0? - In a strict language (SML): return the value 1 - In a lazy language (Haskell): return the value 1

Page 8: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

Page 9: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

Defines a new type name List ...

Page 10: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

Defines a new type name List ...and two constructors, Nil and Cons.

Page 11: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

The type List is parameterized by the type parameter a which represents the type of the list elements (think of templates in C++)

Page 12: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

The constructor Nil has no arguments ...

Page 13: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

The constructor Nil has no arguments ...but the constructor Cons has two ...

Page 14: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

The constructor Nil has no arguments ...but the constructor Cons has two ...the first is a list element ...

Page 15: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

The constructor Nil has no arguments ...but the constructor Cons has two ...the first is a list element ...and the second is the rest of the list.

Page 16: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

Some examples of lists:

Cons 1 (Cons 2 (Cons 3 Nil)) :: List IntCons True (Cons False (Cons False Nil)) :: List Bool

Page 17: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

Some examples of lists:

Cons 1 (Cons 2 (Cons 3 Nil)) :: List IntCons True (Cons False (Cons False Nil)) :: List Bool

The type of the list elements instantiate thetype parameter of List

Page 18: Functional languages and how to implement them

Data structures

data List a = Nil | Cons a (List a)

Some examples of lists:

Cons 1 (Cons 2 (Cons 3 Nil)) :: List IntCons True (Cons False (Cons False Nil)) :: List Bool

The type of the list elements instantiate thetype parameter of List

Page 19: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

Defines the function take; take n xs returns the first n elements of xs or xs if xs is shorter than n

Page 20: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

Definition by pattern matching; a kind of implicit case statement.The first equation that matches is selected.

Page 21: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A literal pattern matches if the argument is that literal(in this case 0) ...

Page 22: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A literal pattern matches if the argument is that literal(in this case 0) ...a variable pattern matches any value (and binds the variable to it) ...

Page 23: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A literal pattern matches if the argument is that literal(in this case 0) ...a variable pattern matches any value (and binds the variable to it) ...so the first equation is chosen if the first argument is 0

Page 24: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A constructor pattern matches if ...

Page 25: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A constructor pattern matches if ...the argument is built with the same constructor ...

Page 26: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A constructor pattern matches if ...the argument is built with the same constructor ...and the component patterns match the values of the componentsof the argument ...

Page 27: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

A constructor pattern matches if ...the argument is built with the same constructor ...and the component patterns match the values of the componentsof the argument ...so the second equation is chosen if

the first argument is not zero, andthe second argument is not the empty list

Page 28: Functional languages and how to implement them

Computing with data structures

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

The function take is polymorphic; its type istake :: Int -> List a -> List a

since the list elements are only extracted from and stored indata structures

Page 29: Functional languages and how to implement them

Higher order functions

filter p (Cons x xs) = if p(x) then Cons x (filter p xs) else filter p xsfilter p Nil = Nil

The parameter p is a function ...

Page 30: Functional languages and how to implement them

Higher order functions

filter p (Cons x xs) = if p(x) then Cons x (filter p xs) else filter p xsfilter p Nil = Nil

The parameter p is a function ...and filter p xs returns the elements of xs for which p returns True

Page 31: Functional languages and how to implement them

Lazy evaluation

sieve (Cons x xs) = Cons x (sieve (filter g xs)) where g y = remainder y x /= 0

from n = Cons n (from (n+1))

primes n = take n (sieve (from 2))

Compute the first n primes as the first n elements of the(infinite) list of all primes

Page 32: Functional languages and how to implement them

Lazy evaluation

sieve (Cons x xs) = Cons x (sieve (filter g xs)) where g y = remainder y x /= 0

from n = Cons n (from (n+1))

primes n = take n (sieve (from 2))

Compute the first n primes as the first n elements of the(infinite) list of all primes

Page 33: Functional languages and how to implement them

Lazy evaluation

sieve (Cons x xs) = Cons x (sieve (filter g xs)) where g y = remainder y x /= 0

from n = Cons n (from (n+1))

primes n = take n (sieve (from 2))

Compute the first n primes as the first n elements of the(infinite) list of all primes

Page 34: Functional languages and how to implement them

Representing data structures

Header

list element

next element

GC info

Constructor #2

Constructor #Nil 1Cons 2

In the stack or In the heap or In the text segment in registers in the data segment

Header

Value (e.g. 1)

Cons node Cons descriptor

Page 35: Functional languages and how to implement them

Representing functions

sieve (Cons x xs) = Cons x (sieve (filter g xs)) where g y = remainder y x /= 0

The function g is passed to filter; how is it represented?

Page 36: Functional languages and how to implement them

Representing functions

sieve (Cons x xs) = Cons x (sieve (filter g xs)) where g y = remainder y x /= 0

The variable x is free in the body of g, so just a code pointeris not enough!

Page 37: Functional languages and how to implement them

Representing functions

Header

value of x

GC info

Code for thebody of g

Header

Value (e.g. 1)

Function node Function descriptor

This pointer ispassed tofilter

Page 38: Functional languages and how to implement them

Implementing lazy evaluation

from n = Cons n (from (n+1))

The function from produces its result one element at a time(Just In Time evaluation!)

Page 39: Functional languages and how to implement them

Implementing lazy evaluation

from n = Cons n (from (n+1))

The suspended computation contains the free variable n

Page 40: Functional languages and how to implement them

Implementing lazy evaluation

Header

value of n

GC info

Code forevaluating the

expressionfrom (n+1)

Header

Value (e.g. 1)

Thunk node Thunk descriptor

This pointer isstored in the Cons node

Page 41: Functional languages and how to implement them

Implementing lazy evaluation

from n = Cons n (thunk from (thunk (eval n)+1))

Thunks and evals can be made explicit in an intermediate languagefor lazy evaluation (Faxén -95, ...)

Page 42: Functional languages and how to implement them

Why lazy functional programs are (sometimes) slow

There are overheads from some featuresExtra cost for building thunks which are

eventually evaluated (most thunks are)Evaluating a thunk is expensive since it involves

an indirect call (bad for optimization and pipelines)

Polymorphism and GC needs uniform representations; thunks force this representation to be boxed

Difficult to make array operations efficient

Page 43: Functional languages and how to implement them

Why lazy functional programs are (sometimes) slow

An inefficient programming style is encouragedMany small functionsFrequent use of higher order functionsLinked data structures rather than monolithic

onesMany intermediate data structures

But this style is good for programmers!

Page 44: Functional languages and how to implement them

Optimizing functional programs

Standard optimizationsInlining, constant propagation and folding, etc

Optimizations of lazy evaluationStrictness analysisCheap eagerness (Faxén -95, -00, -02)Sharing analysis (to avoid updates) (Faxén -97)

Representation analysis (Faxén -99) Deforestation (fusion) Cloning (Faxén -01)

Page 45: Functional languages and how to implement them

Strictness analysis

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

The function take is strict in its first argument since it is necessaryto know its value in order to produce any output ...

Page 46: Functional languages and how to implement them

Strictness analysis

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

The function take is strict in its first argument since it is necessaryto know its value in order to produce any output ...because it is needed for pattern matching

Page 47: Functional languages and how to implement them

Strictness analysis

take 0 xs = Niltake n (Cons y ys) = Cons y (take (n-1) xs)take n Nil = Nil

The function take is not strict in its second argument since it is not necessary to know its value if the first argument is 0

Page 48: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from (thunk (eval n)+1))

primes n = take n (thunk sieve (from 2))

The function from is not strict since it can produce a Cons nodewithout using its argument ...

Page 49: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from (thunk (eval n)+1))

primes n = take n (thunk sieve (from 2))

The function from is not strict since it can produce a Cons nodewithout using its argument ...so the thunk can not be eliminated by strictness analysis

Page 50: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from (thunk (eval n)+1))

primes n = take n (thunk sieve (from 2))

Only the eval is expensive in the thunk body ...

Page 51: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from (thunk (eval n)+1))

primes n = take n (thunk sieve (from 2))

Only the eval is expensive in the thunk body ...and only if n can bound to a thunk ...

Page 52: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from (thunk (eval n)+1))

primes n = take n (thunk sieve (from 2))

Only the eval is expensive in the thunk body ...and only if n can bound to a thunk ...which it unfortunately can since the thunk is passed to from ...

Page 53: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from ( (eval n)+1))

primes n = take n (thunk sieve (from 2))

Only the eval is expensive in the thunk body ...and only if n can bound to a thunk ...which it unfortunately can since the thunk is passed to from ...but if the thunk is eliminated, the eval becomes cheap ...

Page 54: Functional languages and how to implement them

Cheap eagerness

from n = Cons n (thunk from ( ( n)+1))

primes n = take n (thunk sieve (from 2))

Only the eval is expensive in the thunk body ...and only if n can bound to a thunk ...which it unfortunately can since the thunk is passed to from ...but if the thunk is eliminated, the eval becomes cheap ...and can even be eliminated!

Page 55: Functional languages and how to implement them

Cheap eagerness

Cheap eagerness is about speculative evaluationOnly legal if the speculated computation

terminates with no run-time errorOnly good if the speculated expression takes

little time to evaluate or is very likely to be evaluated anyway

Reduces execution time by 12-58% (Faxén -00)

Page 56: Functional languages and how to implement them

Cloning

Several versions of each function is generatedDifferent versions optimized for different call sitesParticularly important for representation analysis

Code growth might be a problemIf identical clones are shared, code growth is

typically at most 20%Some programs actually shrink!

Reduces execution time by 11-29%

Page 57: Functional languages and how to implement them

Conclusion

Functional languages are good for programmersProgramming on a high level of abstractionSubprograms can be combined in interesting

ways

Lazy languages in particular are not efficientHigh overheadsEncourage inefficient programming style

But the compiler can save the day!