# Lazy Functional Programming in Haskell

Post on 21-Jan-2016

22 views

DESCRIPTION

Lazy Functional Programming in Haskell. H. Conrad Cunningham, Yi Liu, and Hui Xiong Software Architecture Research Group Computer and Information Science University of Mississippi. Programming Language Paradigms. Imperative languages have implicit states use commands to modify state - PowerPoint PPT PresentationTRANSCRIPT

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

Software Architecture Research GroupComputer and Information ScienceUniversity of Mississippi

Programming Language ParadigmsImperative languages have implicit statesuse commands to modify stateexpress how something is computedinclude C, Pascal, Ada,

Declarative languageshave no implicit statesuse expressions that are evaluatedexpress what is to be computedhave different underlying modelsfunctions: Lisp (Pure), ML, Haskell, spreadsheets? SQL?relations (logic): Prolog (Pure) , Parlog,

Orderly Expressions andDisorderly StatementsValues of x and y depend upon order of execution of statements

x represents different values in different contexts

Why Use Functional Programming?Referential transparencysymbol always represents the same valueeasy mathematical manipulation, parallel execution, etc.Expressive and concise notationHigher-order functionstake/return functionspowerful abstraction mechanismsLazy evaluationdefer evaluation until result needednew algorithmic approaches

Why Teach/Learn FP and Haskell?Introduces new problem solving techniquesImproves ability to build and use higher-level procedural and data abstractionsHelps instill a desire for elegance in design and implementationIncreases comfort and skill in use of recursive programs and data structuresDevelops understanding of programming languages features such as type systemsIntroduces programs as mathematical objects in a natural way

Haskell and HugsHaskellStandard functional language for research Work began in late 1980sWeb site: http://www.haskell.orgHugs Interactive interpreter for Haskell 98Download from: http://www.haskell.org/hugs

Quicksort AlgorithmIf sequence is empty, then it is sortedTake any element as pivot valuePartition rest of sequence into two partselements < pivot valueelements >= pivot valueSort each part using QuicksortResult is sorted part 1, followed by pivot, followed by sorted part 2

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

- Quicksort in Haskellqsort :: [Int] -> [Int]qsort [] = [] qsort (x:xs) = qsort lt ++ [x] ++ qsort greq where lt = [y | y
Types Basic typesBoolIntFloatDoubleCharStructured typeslists [] tuples ( , ) user-defined typesfunctions ->

Definitions Definitions name :: type e.g.:size :: Intsize = 12 - 3Function 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)

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

Another Factorial Functionfact1 :: 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

Yet Another Factorial Functionfact2 :: 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)

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

List Appendinfixr 5 ++ -- infix operator

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

Abstraction: Higher-Order FunctionssquareAll :: [Int] -> [Int]squareAll [] = []squareAll (x:xs) = (x * x) : squareAll xs

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

MapAbstract 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

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

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)

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

Fold RightAbstract 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

Divide and Conquer FunctiondivideAndConquer :: (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))

Divide and Conquer Functionfib :: 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

Currying and Partial Evaluationadd :: (Int,Int) -> Intadd (x,y) = x + y

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

add takes one argument and returns a functionTakes 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)

- Using Partial Evaluation doublePos :: [Int] -> [Int] doublePos xs = map ((*) 2) (filter ((
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 [ [1, 2, 4, 8,], [1, 3, 9, 27,], [1, 4,16, 64,], [1, 5, 25,125,], ]

Sieve of Eratosthenes AlgorithmGenerate list 2, 3, 4, Mark first element p of list as primeDelete all multiples of p from list Return to step 2

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

sieve (p:xs) = [x | x

Hammings ProblemProduce the list of integersincreasing order (hence no duplicate values)begins with 1if n is in list, then so is 2*n, 3*n, and 5*nlist contains no other elements

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

Hamming Programham :: [Int]ham = 1 : merge3 [ 2*n | n [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

User-Defined Data Typesdata 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

Other Important Haskell FeaturesType inferencingType classes and overloadingRich set of built-in typesExtensive librariesModulesMonads for purely functional I/O and other actions

Other Important FP TopicsProblem solving and program design techniquesAbstract data typesProofs about functional program propertiesProgram synthesisReduction modelsParallel execution (dataflow interpretation)

Haskell-based TextbooksSimon 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

Other FP Textbooks Of InterestFethi Rabhi and Guy Lapalme. Algorithms: A Functional Approach, Addison Wesley, 1999.

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

AcknowledgementsIndividuals 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.

Recommended