Lazy Functional Programming in Haskell H. Conrad Cunningham, Yi Liu, and Hui Xiong Software...

Post on 28-Dec-2015

218 views 0 download

Transcript of Lazy Functional Programming in Haskell H. Conrad Cunningham, Yi Liu, and Hui Xiong Software...

Lazy Functional Programming in Haskell

H. Conrad Cunningham, Yi Liu, and Hui Xiong

Software Architecture Research GroupComputer and Information Science

University of Mississippi

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, …

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

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

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

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

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

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 ); } }

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]

2-Apr-2004 10

Types

• Basic types– Bool

– Int

– Float

– Double

– Char

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

– functions ->

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

2-Apr-2004 12

Factorial Function

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

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

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)

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

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)

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

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

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

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)

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

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

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))

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

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)

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 ]

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,…], … ]

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

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, …

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

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

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

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)

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

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.

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.