Create Presentation
Download Presentation

Download Presentation
## COMP313A Functional Programming (1)

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -

**Main Differences with Imperative Languages**• Say more about what is computed as opposed to how • Pure functional languages have no • variables • assignments • other side effects • Means no loops**Differences…**• Imperative languages have an implicit state (state of variables)that ismodified (side effect). • Sequencing is important to gain precise, deterministic control over the state • assignment statement needed to change the binding for a particular variable (alter the implicit state)**Imperative factorialn:=x;**a:=1;while n > 0 do begin a:= a * n; n := n-1; end;**Differences**• Declarative languages have no implicitstate • Program with expressions • The state is carried around explicitly • e.g. the formal parameter n in factorial • Looping is accomplished with recursion rather than sequencing**Haskell**fac ::Int -> Int fac n | n == 0 = 1 | n > 0 = fac(n-1) * n | otherwise = 0 Scheme (define fac (lambda (n) (if (= n 0) 1 (* n (fac (- n 1))))))**Advantages**• similar to traditional mathematics • referential transparency makes programs more readable • higher order functions give great flexibility • concise programs**Referential Transparency**• the value of a function depends only on the values of its parameters for example Haskell …x + x… where x = f a**Evolution of Functional languagesLambda Calculus**• Alonzo Church • Captures the essence of functional programming • Formalism for expressing computation by functions • Lambda abstraction • In Scheme • In Haskell (lx. + 1 x) (lambda(x) (+ 1 x))) add1 :: Int -> Int add1 x = 1 + x**Lambda Calculus…**• application of expressions • reduction rule that substitutes 2 for x in the lambda (beta reduction) (lx. + 1 x) 2 (lx. + 1 x) 2 Þ (+ 1 2) Þ 3 (lx. * x x) (+ 2 3) i.e. (+ 2 3) / x)**Lambda Calculus…**• (lx.E) • variable x is bound by the lambda • the scope of the binding is the expression E • (lx. + y x) • (lx. + y x)2 Þ (+ y 2) • (lx. + ((ly. ((lx. * x y) 2)) x) y) Þ**Lambda Calculus…**• Each lambda abstraction binds only one variable • Need to bind each variable with its own lambda. (lx. (ly. + x y))**Lisp**• McCarthy late 1950s • Used Lambda Calculus for anonymous functions • List processing language • First attempt built on top of FORTRAN**LISP…**• McCarthy’s main contributions were • the conditional expression and its use in writing recursive functions Scheme (define fac (lambda (n) (if (= n 0) 1 (if (> n 0) (* n (fac (- n 1))) 0)))) Scheme (define fac2 (lambda (n) (cond ((= n 0) 1) ((> n 0) (* n (fac2 (- n 1)))) (else 0)))) Haskell fac ::Int -> Int fac n | n == 0 = 1 | n > 0 = fac(n-1) * n | otherwise = 0 Haskell fac :: Int -> Int fac n = if n == 0 then 1 else if n > 0 then fac(n-1) * n else 0**Lisp…**2. the use of lists and higher order operations over lists such as mapcar Scheme (define mymap (lambda (f a b) (cond ((and (null? a) (null? b)) '()) (else (cons (f (first a) (first b)) (mymap f (rest a) (rest b))))))) Haskell mymap :: (Int -> Int-> Int) -> [Int] -> [Int] ->[Int] mymap f [] [] = [] mymap f (x:xs) (y:ys) = f x y : mymap f xs ys add :: Int -> Int -> Int add x y = x + y Scheme (mymap + ’(3 4 6) ’(5 7 8)) Haskell mymap add [3, 4, 6] [5, 7, 8]**Lisp**• cons cell and garbage collection of unused cons cells Scheme (cons ’1 ’(3 4 5 7)) (1 3 4 5 7) Haskell cons :: Int -> [Int] -> [Int] cons x xs = x:xs Scheme (define mymap (lambda (f a b) (cond ((and (null? a) (null? b)) '()) (else (cons (f (first a) (first b)) (mymap f (first a) (first b)))))))**Lisp…**• use of S-expressions to represent both program and data An expression is an atom or a list But a list can hold anything…**Scheme**(cons ’1 ’(3 4 5 7)) (1 3 4 5 7) Scheme (define mymap (lambda (f a b) (cond ((and (null? a) (null? b)) '()) (else (cons (f (first a) (first b)) (mymap f (first a) (first b)))))))**ISWIM**• Peter Landin – mid 1960s • If You See What I Mean Landon wrote “…can be looked upon as an attempt to deliver Lisp from its eponymous commitment to lists, its reputation for hand-to-mouth storage allocation, the hardware dependent flavour of its pedagogy, its heavy bracketing, and its compromises with tradition”**Iswim…**• Contributions • Infix syntax • let and where clauses, including a notion of simultaneous and mutually recursive definitions • the off side rule based on indentation • layout used to specify beginning and end of definitions • Emphasis on generality • small but expressive core language**let in Scheme**• let* - the bindings are performed sequentially (let* ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) Þ ? (* z x))) (let* ((x 2) (y 3)) Þ ? (* x y))**let in Scheme**• let - the bindings are performed in parallel, i.e. the initial values are computed before any of the variables are bound (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) Þ ? (* z x))) (let ((x 2) (y 3)) Þ ? (* x y))**letrec in Scheme**• letrec – all the bindings are in effect while their initial values are being computed, allows mutually recursive definitions (letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88))**ML**• Gordon et al 1979 • Served as the command language for a proof generating system called LCF • LCF reasoned about recursive functions • Comprised a deductive calculus and an interactive programming language – Meta Language (ML) • Has notion of references much like locations in memory • I/O – side effects • But encourages functional style of programming**ML**• Type System • it is strongly and statically typed • uses type inference to determine the type of every expression • allows polymorphic functions • Has user defined ADTs**SASL, KRC, and Miranda**add x y = + x y add 1 • Used guards • Higher Order Functions • Lazy Evaluation • Currying switch :: Int -> a -> a -> a switch n x y | n > 0 = x | otherwise = y SASL fac n = 1, n = 0 = n * fac (n-1), n>0 multiplyC :: Int -> Int -> Int Versus multiplyUC :: (Int, Int) -> Int Haskell fac n | n ==0 = 1 | n >0 = n * ( fac(n-1)**SASL, KRC and Miranda**• KRC introduced list comprehension • Miranda borrowed strong data typing and user defined ADTs from ML comprehension :: [Int] -> [Int] comprehension ex = [2 * n | n <- ex]**LISP…**• McCarthy’s main contributions were • the conditional expression and its use in writing recursive functions Scheme (define fac (lambda (n) (if (= n 0) 1 (if (> n 0) (* n (fac (- n 1))) 0)))) Scheme (define fac2 (lambda (n) (cond ((= n 0) 1) ((> n 0) (* n (fac2 (- n 1)))) (else 0)))) Haskell fac ::Int -> Int fac n | n == 0 = 1 | n > 0 = fac(n-1) * n | otherwise = 0 Haskell fac :: Int -> Int fac n = if n == 0 then 1 else if n > 0 then fac(n-1) * n else 0**Lisp…**2. the use of lists and higher order operations over lists such as mapcar Scheme (define mymap (lambda (f a b) (cond ((and (null? a) (null? b)) '()) (else (cons (f (first a) (first b)) (mymap f (rest a) (rest b))))))) Haskell mymap :: (Int -> Int-> Int) -> [Int] -> [Int] ->[Int] mymap f [] [] = [] mymap f (x:xs) (y:ys) = f x y : mymap f xs ys add :: Int -> Int -> Int add x y = x + y Scheme (mymap + ’(3 4 6) ’(5 7 8)) Haskell mymap add [3, 4, 6] [5, 7, 8]**Lisp**• cons cell and garbage collection of unused cons cells Scheme (cons ’1 ’(3 4 5 7)) (1 3 4 5 7) Haskell cons :: Int -> [Int] -> [Int] cons x xs = x:xs Scheme (define mymap (lambda (f a b) (cond ((and (null? a) (null? b)) '()) (else (cons (f (first a) (first b)) (mymap f (first a) (first b)))))))**Lisp…**• use of S-expressions to represent both program and data An expression is an atom or a list But a list can hold anything…**Scheme**(cons ’1 ’(3 4 5 7)) (1 3 4 5 7) Scheme (define mymap (lambda (f a b) (cond ((and (null? a) (null? b)) '()) (else (cons (f (first a) (first b)) (mymap f (first a) (first b)))))))**ISWIM**• Peter Landin – mid 1960s • If You See What I Mean Landon wrote “…can be looked upon as an attempt to deliver Lisp from its eponymous commitment to lists, its reputation for hand-to-mouth storage allocation, the hardware dependent flavour of its pedagogy, its heavy bracketing, and its compromises with tradition”**Iswim…**• Contributions • Infix syntax • let and where clauses, including a notion of simultaneous and mutually recursive definitions • the off side rule based on indentation • layout used to specify beginning and end of definitions • Emphasis on generality • small but expressive core language**let in Scheme**• let* - the bindings are performed sequentially (let* ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) Þ ? (* z x))) (let* ((x 2) (y 3)) Þ ? (* x y))**let in Scheme**• let - the bindings are performed in parallel, i.e. the initial values are computed before any of the variables are bound (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) Þ ? (* z x))) (let ((x 2) (y 3)) Þ ? (* x y))**letrec in Scheme**• letrec – all the bindings are in effect while their initial values are being computed, allows mutually recursive definitions (letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88))**Emacs was/is written in LISP**• Very popular in AI research**ML**• Gordon et al 1979 • Served as the command language for a proof generating system called LCF • LCF reasoned about recursive functions • Comprised a deductive calculus and an interactive programming language – Meta Language (ML) • Has notion of references much like locations in memory • I/O – side effects • But encourages functional style of programming**ML**• Type System • it is strongly and statically typed • uses type inference to determine the type of every expression • allows polymorphic functions • Has user defined ADTs**SASL, KRC, and Miranda**add x y = + x y silly_add x y = x add 4 (3 * a) • Used guards • Higher Order Functions • Lazy Evaluation • Currying switch :: Int -> a -> a -> a switch n x y | n > 0 = x | otherwise = y SASL fac n = 1, n = 0 = n * fac (n-1), n>0 multiplyC :: Int -> Int -> Int Versus multiplyUC :: (Int, Int) -> Int Haskell fac n | n ==0 = 1 | n >0 = n * fac(n-1)**SASL, KRC and Miranda**• KRC introduced list comprehension • Miranda borrowed strong data typing and user defined ADTs from ML comp_example :: [Int] -> [Int] comp_example ex = [2 * n | n <- ex]**The Move to Haskell**• Lots of functional languages in late 1970’s and 1980’s • Tower of Babel • Among these was Hope • strongly typed • polymorphism but explicit type declarations as part of all function definitions • simple module facility • user-defined concrete data types with pattern matching**The Move to Haskell**• 1987 – considered lack of common language was hampering the adoption of functional languages • Haskell was born • higher order functions • lazy evaluation • static polymorphic typing • user-defined datatypes • pattern matching • list comprehensions**Haskell…**• as well • module facility • well defined I/O system • rich set of primitive data types**Higher Order Functions**• Functions as first class values • stored as data structures, passed as arguments, returned as results • Function is the primary abstraction mechanism • increase the use of this abstraction • Higher order functions are the “guts” of functional programming**Higher Order FunctionsComputations over lists**• Mapping • add 5 to every element of a list. • add the corresponding elements of 2 lists • Filtering • Selecting the elements with a certain property • Folding • Combine the items in a list in some way**List Comprehension**Double all the elements in a list Using primitive recursion doubleAll :: [Int] -> [Int] doubleAll [] = [] doubleAll x:xs = 2 * x : doubleAll xs Using list comprehension doubleAll :: [Int] -> [Int] doubleAll xs :: [ 2 * x | x <- xs ]**Primitive RecursionversusGeneral Recursion**sum :: [Int] -> Int sum [] = 0 sum (x:xs) = x + sum xs qsort :: [Int] -> [Int] qsort [] = [] qsort (x : xs) = qsort [ y | y<-xs , y<=x] ++ [x] ++ qsort [ y | y <- xs , y>x]