Transcript
Page 1: Lazy Functional Programming  in Haskell

Lazy Functional Programming in Haskell

H. Conrad Cunningham, Yi Liu, and Hui Xiong

Software Architecture Research GroupComputer and Information Science

University of Mississippi

Page 2: Lazy Functional Programming  in Haskell

2-Apr-2004 2

Programming Language Paradigms

• Imperative languages – have implicit states– use commands to modify state– express how something is computed– include C, Pascal, Ada, …

• Declarative languages– have no implicit states– use expressions that are evaluated– express what is to be computed– have different underlying models

• functions: Lisp (Pure), ML, Haskell, …spreadsheets? SQL?• relations (logic): Prolog (Pure) , Parlog, …

Page 3: Lazy Functional Programming  in Haskell

2-Apr-2004 3

Orderly Expressions andDisorderly Statements

{ x = 1; y = 2; z = 3 }

x = 3 * x + 2 * y + z

y = 5 * x – y + 2 * z

Values of x and y depend upon order of execution of statements

x represents different values in different contexts

Page 4: Lazy Functional Programming  in Haskell

2-Apr-2004 4

Why Use Functional Programming?

• Referential transparency– symbol always represents the same value– easy mathematical manipulation, parallel execution, etc.

• Expressive and concise notation• Higher-order functions

– take/return functions– powerful abstraction mechanisms

• Lazy evaluation– defer evaluation until result needed– new algorithmic approaches

Page 5: Lazy Functional Programming  in Haskell

2-Apr-2004 5

Why Teach/Learn FP and Haskell?

• Introduces new problem solving techniques• Improves ability to build and use higher-level

procedural and data abstractions• Helps instill a desire for elegance in design and

implementation• Increases comfort and skill in use of recursive

programs and data structures• Develops understanding of programming languages

features such as type systems• Introduces programs as mathematical objects in a

natural way

Page 6: Lazy Functional Programming  in Haskell

2-Apr-2004 6

Haskell and Hugs

• Haskell– Standard functional language for research – Work began in late 1980s– Web site: http://www.haskell.org

• Hugs – Interactive interpreter for Haskell 98– Download from:

http://www.haskell.org/hugs

Page 7: Lazy Functional Programming  in Haskell

2-Apr-2004 7

Quicksort Algorithm

• If sequence is empty, then it is sorted

• Take any element as pivot value

• Partition rest of sequence into two parts1. elements < pivot value

2. elements >= pivot value

• Sort each part using Quicksort

• Result is sorted part 1, followed by pivot, followed by sorted part 2

Page 8: Lazy Functional Programming  in Haskell

2-Apr-2004 8

Quicksort in C

qsort( a, lo, hi ) int a[ ], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l + 1; while ((h > l) && (a[h] >= p)) h = h – 1 ; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); t = a[l]; a[l] = a[hi]; a[hi] = t; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }

Page 9: Lazy Functional Programming  in Haskell

2-Apr-2004 9

Quicksort in Haskell

qsort :: [Int] -> [Int]qsort [] = [] qsort (x:xs) = qsort lt ++ [x] ++ qsort greq where lt = [y | y <- xs, y < x] greq = [y | y <- xs, y >= x]

Page 10: Lazy Functional Programming  in Haskell

2-Apr-2004 10

Types

• Basic types– Bool

– Int

– Float

– Double

– Char

• Structured types– lists [] – tuples ( , ) – user-defined types

– functions ->

Page 11: Lazy Functional Programming  in Haskell

2-Apr-2004 11

• Definitions name :: type

e.g.:size :: Intsize = 12 - 3

• Function definitions name :: t1 -> t2 -> … -> tk -> t

function name types of type of result arguments e.g.: exOr :: Bool -> Bool -> Bool exOr x y = (x || y) && not (x && y)

Definitions

Page 12: Lazy Functional Programming  in Haskell

2-Apr-2004 12

Factorial Function

fact1 :: Int -> Intfact1 n -- use guards on two equations | n == 0 = 1 | n > 0 = n * fact1 (n-1)

Page 13: Lazy Functional Programming  in Haskell

2-Apr-2004 13

Another Factorial Function

fact1 :: Int -> Intfact1 n -- use guards on two equations

| n == 0 = 1 | n > 0 = n * fact1 (n-1)

fact2 :: Int -> Intfact2 0 = 1 -- use pattern matchingfact2 (n+1) = (n+1) * fact n

fact1 and fact2 represent the same function

Page 14: Lazy Functional Programming  in Haskell

2-Apr-2004 14

Yet Another Factorial Function

fact2 :: Int -> Intfact2 0 = 1fact2 (n+1) = (n+1) * fact n

fact3 :: Int -> Intfact3 n = product [1..n] -- library functions

fact3 differs slightly from fact1 and factConsider fact2 (-1) and fact3 (-1)

Page 15: Lazy Functional Programming  in Haskell

2-Apr-2004 15

List Cons and Length

(x:xs) on right side of defining equation means to form new list with x as head element and xs as tail list – colon is “cons”

(x:xs) on left side of defining equation means to match a list with at least one element, x gets head element, xs gets tail list

[ x1, x2, x3 ] gives explicit list of elements, [] is nil list

len :: [a] -> Int -- polymorphic list argumentlen [] = 0 -- nil listlen (x:xs) = 1 + len xs -- non-nil list

Page 16: Lazy Functional Programming  in Haskell

2-Apr-2004 16

List Append

infixr 5 ++ -- infix operator

-- note polymorphism(++) :: [a] -> [a] -> [a][] ++ xs = xs -- infix pattern match(x:xs) ++ ys = x:(xs ++ ys)

Page 17: Lazy Functional Programming  in Haskell

2-Apr-2004 17

Abstraction: Higher-Order Functions

squareAll :: [Int] -> [Int]squareAll [] = []squareAll (x:xs) = (x * x) : squareAll xs

lengthAll :: [[a]] -> [Int]lengthAll [] = []lenghtAll (xs:xss) = (length xs) : lengthAll xss

Page 18: Lazy Functional Programming  in Haskell

2-Apr-2004 18

Map

Abstract different functions applied as function argument to a library function called map

map :: (a -> b) -> [a] -> [b]map f [] = []map f (x:xs) = (f x) : map f xs

squareAll xs = map sq xs where sq x = x * x -- local function defsquareAll’ xs = map (\x -> x * x) xs -- anonymous function -- or lambda expressionlengthAll xs = map length xs

Page 19: Lazy Functional Programming  in Haskell

2-Apr-2004 19

Another Higher-Order Function

getEven :: [Int] -> [Int]getEven [] = []getEven (x:xs) | even x = x : getEven xs | otherwise = getEven xs

doublePos :: [Int] -> [Int]doublePos [] = []doublePos (x:xs) | 0 < x = (2 * x) : doublePos xs | otherwise = doublePos xs

Page 20: Lazy Functional Programming  in Haskell

2-Apr-2004 20

Filter

filter :: (a -> Bool) -> [a] -> [a]filter _ [] = []filter p (x:xs) | p x = x : xs' | otherwise = xs' where xs' = filter p xs

getEven :: [Int] -> [Int]getEven xs = filter even xs -- use library function

doublePos :: [Int] -> [Int]doublePos xs = map dbl (filter pos xs) where dbl x = 2 * x pos x = (0 < x)

Page 21: Lazy Functional Programming  in Haskell

2-Apr-2004 21

Yet Another Higher-Order Function

sumlist :: [Int] -> Intsumlist [] = 0 -- nil list sumlist (x:xs) = x + sumlist xs -- non-nil

concat' :: [[a]] -> [a]concat' [] = [] -- nil list of lists concat' (xs:xss) = xs ++ concat' xss -- non-nil

Page 22: Lazy Functional Programming  in Haskell

2-Apr-2004 22

Fold Right

Abstract different binary operators to be applied

foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z -- binary op, identity, listfoldr f z (x:xs) = f x (foldr f z xs)

sumlist :: [Int] -> Intsumlist xs = foldr (+) 0 xs

concat' :: [[a]] -> [a]concat' xss = foldr (++) [] xss

Page 23: Lazy Functional Programming  in Haskell

2-Apr-2004 23

Divide and Conquer Function

divideAndConquer :: (a -> Bool) -- trivial -> (a -> b) -- simplySolve -> (a -> [a]) -- decompose -> (a -> [b] -> b) -- combineSolutions -> a -- problem -> b

divideAndConquer trivial simplySolve decompose combineSolutions problem = solve problem where solve p | trivial p = simplySolve p | otherwise = combineSolutions p map solve (decompose p))

Page 24: Lazy Functional Programming  in Haskell

2-Apr-2004 24

Divide and Conquer Function

fib :: Int -> Intfib n = divideAndConquer trivial simplySolve decompose combineSolutions n where trivial 0 = True trivial 1 = True trivial (m+2)= False simplySolve 0 = 0 simplySolve 1 = 1 decompose m = [m-1,m-2] combineSolutions _ [x,y] = x + y

Page 25: Lazy Functional Programming  in Haskell

2-Apr-2004 25

Currying and Partial Evaluation

add :: (Int,Int) -> Intadd (x,y) = x + y

? add(3,4) => 7? add (3, ) => error

add’ takes one argument and returns a function

Takes advantage of Currying

add' :: Int->(Int->Int) add' x y = x + y

? add’ 3 4 => 7 ? add’ 3

(add’ 3) :: Int -> Int (add’ 3) x = 3 + x

((+) 3)

Page 26: Lazy Functional Programming  in Haskell

2-Apr-2004 26

Using Partial Evaluation

doublePos :: [Int] -> [Int] doublePos xs = map ((*) 2) (filter ((<) 0) xs)

• Using operator section notation

doublePos xs = map (*2) (filter (0<) xs)

• Using list comprehension notation

doublePos xs = [ 2*x | x <- xs, 0< x ]

Page 27: Lazy Functional Programming  in Haskell

2-Apr-2004 27

Lazy Evaluation Do not evaluate an expression unless its value is needed

iterate :: (a -> a) -> a -> [a]iterate f x = x : iterate f (f x)

interate (*2) 1 => [1, 2, 4, 8, 16, …]

powertables :: [[Int]]powertables = [ iterate (*n) 1 | n <- [2..] ]

powertables => [ [1, 2, 4, 8,…], [1, 3, 9, 27,…], [1, 4,16, 64,…], [1, 5, 25,125,…], … ]

Page 28: Lazy Functional Programming  in Haskell

2-Apr-2004 28

Sieve of Eratosthenes Algorithm

1. Generate list 2, 3, 4, … 2. Mark first element p of list as prime3. Delete all multiples of p from list 4. Return to step 2

primes :: [Int]primes = map head (iterate sieve [2..])

sieve (p:xs) = [x | x <- xs, x `mod` p /= 0 ]

takewhile (< 10000) primes

Page 29: Lazy Functional Programming  in Haskell

2-Apr-2004 29

Hamming’s Problem

Produce the list of integers• increasing order (hence no duplicate values)• begins with 1• if n is in list, then so is 2*n, 3*n, and 5*n• list contains no other elements

1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, …

Page 30: Lazy Functional Programming  in Haskell

2-Apr-2004 30

Hamming Program

ham :: [Int]ham = 1 : merge3 [ 2*n | n <- ham ]

[ 3*n | n <- ham ] [ 5*n | n <- ham ]

merge3 :: Ord a => [a] -> [a] -> [a] -> [a]merge3 xs ys zs = merge2 xs (merge2 ys zs)

merge2 xs'@(x:xs) ys'@(y:ys) | x < y = x : merge2 xs ys' | x > y = y : merge2 xs' ys | otherwise = x : merge2 xs ys

Page 31: Lazy Functional Programming  in Haskell

2-Apr-2004 31

User-Defined Data Types

data BinTree a = Empty | Node (BinTree a) a (BinTree a)

height :: BinTree -> Intheight Empty = 0height (Node l v r) = max (height l) (height r) + 1

flatten :: BinTree a -> [a] -- in-order traversalflatten Empty = []flatten (Node l v r) = flatten l ++ [v] ++ flatten r

Page 32: Lazy Functional Programming  in Haskell

2-Apr-2004 32

Other Important Haskell Features

• Type inferencing• Type classes and overloading• Rich set of built-in types• Extensive libraries• Modules• Monads for purely functional I/O and other actions

Page 33: Lazy Functional Programming  in Haskell

2-Apr-2004 33

Other Important FP Topics

• Problem solving and program design techniques• Abstract data types• Proofs about functional program properties• Program synthesis• Reduction models• Parallel execution (dataflow interpretation)

Page 34: Lazy Functional Programming  in Haskell

2-Apr-2004 34

Haskell-based Textbooks

• Simon Thompson. Haskell: The Craft of Functional Programming, Addison Wesley, 1999.

• Richard Bird. Introduction to Functional Programming Using Haskell, second edition, Prentice Hall Europe, 1998.

• Paul Hudak. The Haskell School of Expression, Cambridge University Press, 2000.

• H. C. Cunningham. Notes on Functional Programming with Gofer, Technical Report UMCIS-1995-01, University of Mississippi, Department of Computer and Information Science, Revised January 1997. http://www.cs.olemiss.edu/~hcc/reports/gofer_notes.pdf

Page 35: Lazy Functional Programming  in Haskell

2-Apr-2004 35

Other FP Textbooks Of Interest

• Fethi Rabhi and Guy Lapalme. Algorithms: A Functional Approach, Addison Wesley, 1999.

• Chris Okasaki. Purely Functional Data Structures, Cambridge University Press, 1998.

Page 36: Lazy Functional Programming  in Haskell

2-Apr-2004 36

Acknowledgements

• Individuals who helped me get started teaching lazy functional programming in the early 1990s.

• Mark Jones and others who implemented the Hugs interpreter.

• More than 200 students who have been in my 10 classes on functional programming in the past 14 years.

• Acxiom Corporation for funding some of my recent work on software architecture.


Top Related