# Graphics by ewghwehws

VIEWS: 5 PAGES: 23

• pg 1
```									159.331 Programming Languages
& Algorithms
Lecture 18 - Functional Programming
Languages - Part 2
Higher-Order Functions, Currying, Lazy
Evaluation, Equations and Pattern Matching
159.331            Prog Lang & Alg             1
Higher-Order Functions
• Many (most) imperative languages treat variables and
functions differently (non-orthogonality again!)
• Variables can be manipulated (read, written, passed
around) but functions are “second-class citizens” and can
only be invoked
• Functional languages usually treat functions as first-class
objects, which can be passed around as arguments,
returned as a function result or stored in a data structure
• A function that takes another function as an argument is
called a higher-order function
• This idea is a cornerstone of functional programming.
159.331                Prog Lang & Alg               2
• An important higher-order function is map, which takes a
function and a list as input and returns a new list with the
function applied to each element
map triple [1,2,3,4] =>
[triple 1, triple 2, triple 3, triple 4 ] =>
[3, 6, 9, 12]
• Note we need the capability of passing a function (in this
case “triple”) as an argument to map
• We could of course write a special-case function such as
map_triple, but this has to have a name of its own and is no
longer general - we want our concepts to be reuseable!
• Having the higher-order function capability a language is
powerful - useful if it is not the ugly and hard-to-remember
function-pointer syntax that C and C++offer!

159.331                      Prog Lang & Alg         3
• Functional languages usually offer other built in higher-
order functions
• Fold-right or foldr is used to compute a single result (eg a
sum or product) from a list
foldr (+) 0 [2, 4, 7] is equal to:
( 2 + ( 4 + ( 7 + 0 ) ) ) => 13
• This is Miranda syntax where if an infix operator like
“+” is passed as an argument it must be in parentheses.
• foldr (*) 1 x computes the product of all elements in list x
• foldr (&) True x computes logical “and” of all the
elements in x
• The built-in higher-order functions are type checked

159.331                    Prog Lang & Alg            4
Currying
• Most functional languages support currying or partial
parameterization (named after the logician H.B.Curry)
mult a b = a * b
• Is a function which if applied to two arguments will
compute their product
• In Miranda we can apply it to just one argument, and
the result is another function which takes one
argument, so we can define triple function as:
triple = mult 3
• We say that mult has been “curried” or “partially
parameterised” - its need for args has been partially met
159.331               Prog Lang & Alg               5
• We can define a function to sum a list:
sumlist = foldr (+) 0
• This has provided 2 out of the 3 arguments
required by foldr so the result is a function
that takes one argument (a list) hence:
sumlist [ 5, 9, 20] => 34
• The type of function mult is:
mult :: num -> ( num -> num )
• Which means mult can be regarded as a
function with one argument that returns
another function of type num -> num
159.331                 Prog Lang & Alg         6
Lazy Evaluation
• In evaluating a function the simplest way is to first evaluate
all the arguments then invoke the function.
• eg in:
mult ( fac 3 ) ( fac 4 )
• The function applications (fac 3) and (fac 4) would be
done first in arbitrary order, reducing the expression to
mult 6 24
•   Then mult is applied to its two arguments resulting in 144
•   This is known as applicative order reduction
•   It starts with the inner-most expressions
•   Sometimes we do not want to do it this way…

159.331                  Prog Lang & Alg             7
expression and work inwards, not evaluating sub
expressions until we need their results:
• So: mult (fac 3) (fac 4) is reduced to:
(fac 3) * (fac 4)
• and next to     6 * 24
• and finally     144
• Consider a function cond that is like the ternary
operator ? : in C/C++
cond b x y = x, if b
cond b x y = y, otherwise
• What happens if we applicatively evaluate the three
arguments?

159.331                      Prog Lang & Alg        8
1. One of the args is evaluated needlessly (makes code
slower)
2. If the arg that is evaluated needlessly never terminates,
then the whole expression never terminates
• Often we use this construct to guard against some non-
terminating or incorrect condition
• In functional languages we might want to define the
factorial function:
fac n = cond (n=0)   1   (n * fac (n -1) )
•    If the third argument is always evaluated this will never
terminate (fac 1 invokes fac 0 which invokes fac -1
….
•    These problems have led to the concept of lazy
evaluation
159.331                 Prog Lang & Alg               9
• Lazy evaluation uses normal order
reduction and is where the arguments of a
function are only evaluated when their values
are needed
• Contrast this with applicative order
reduction which is also known as eager
evaluation
• Using lazy evaluation, the following figure
shows how the expression is reduced…

159.331            Prog Lang & Alg              10
159.331   Prog Lang & Alg   11
Strict Semantics
• A language based on eager evaluation is said
to have strict semantics because it always
evaluates the arguments of functions
• A language using lazy evaluation is said to
have non-strict semantics
• Miranda has non-strict semantics so fac in the
example evaluates correctly

159.331             Prog Lang & Alg           12
• Lazy evaluation is also useful for defining and manipulating
(potentially) infinite data structures like open-ended lists or
sets and sequences (as compared with an array which is
finitely bounded)
• In Miranda [1..] denotes the (infinite) list of all positive
integers, and can be manipulated:
hd [1..]                   => 1               || 1st element
hd ( tl [1..] )            => 2               || 2nd element
hd ( tl ( map triple [1..] ))                 => 6 || 2nd element of
|| tripled list
• This works because Miranda will only build the finite part
of the list that is actually needed. Only if we (foolishly)
request the whole list will the system run out of memory
or never terminate eg sumlist [1..] or #[1..]

159.331                   Prog Lang & Alg                       13
I/O in Functional Languages
• I/O is a problem as it is not referentially transparent in
functional languages
• Address this problem by modeling I/O with lazy evaluation
• A functional program takes a list of responses from the
operating system (OS) as input
• It produces a list of requests to the OS where the n’th
• Reading and writing files can be modeled as data requests
and confirmation exchanges with the OS
• With lazy semantics the program can look at the OS
responses when it wants to
• Request and response lists are just streams of messages
159.331               Prog Lang & Alg             14
• Lazy evaluation semantics are costly to implement
(surprise, NOT!)
• Normal order reduction may evaluate an expression more
than once
• Applicative order evaluates expressions exactly once
• double x = x + x
• Normal order evaluates double 23 * 45 as:
double 23 * 45 => 23 * 45 + 23*45 => 1035+23*45 =>
1035 + 1035 => 2070
• Whereas applicative order evaluates more efficiently as:
• double 23 * 45 => double 1035 = 1035 + 1035 => 2070

159.331                 Prog Lang & Alg             15
Graph Reduction
• Graph reduction is a technique for solving this
inefficiency problem of lazy evaluation of expressions
• It allows us to specify we want expressions evaluates
zero or one times but not multiple times - adds some
complexity to the compiler
• There is also a small overhead in postponing evaluation
but this can be optimised out by the compiler
• Not all languages provide lazy evaluation
• Languages that do not will have some feature that
does provide lazy semantics eg the if-statement and
its variants in imperative languages - recall also the
short-cut logical operators in C/C++
159.331               Prog Lang & Alg              16
Equations and Pattern Matching
• Modern functional languages like Miranda or Haskell
have a capability for specifying equational functions (or
just “equations”)
• We have seen examples like if x>0…otherwise…
• This idea generalises to allow choices based on patterns
with syntax like:
<pattern> = <expression>, condition
• Where the condition part is optional
• The pattern can use formal parameters etc
• If a function is invoked the system tries to find a match
159.331                 Prog Lang & Alg              17
• In Miranda (and most cases of this) it is the first
textually occuring match that succeeds that will be
chosen
• Our cond example becomes the set of equations:
cond True x y = x
cond False x y = y
• And fac can be written as:
fac 0 = 1
fac (n+1) = (n+1) * fac n
• 1st pattern matches if the argument is equal to zero
and more subtly the second pattern matches only if
the argument is greater than or equal to 1
159.331              Prog Lang & Alg          18
• In general a numerical expression appearing
ina pattern may have the form v + c where v
is a variable and c is a literal constant
• The pattern only matches if v can be set to a
non-negative value
• More general numerical expressions are
disallowed (to prevent ambiguities)
• For example f(n+m) = n *m is ambiguous
and hence illegal - a call like f 9 could result
in 1*8 or 2*7 or other combinations

159.331              Prog Lang & Alg           19
• Patterns can also contain lists
• We can implement the length (of a list) function:
length [ ] = 0
length ( a : b) = 1 + (length b)
• Pattern in 1st equation specifies an empty list,
second will only match if argument is a non-empty
list, and then makes a recursive call passing the tail
of the list as the new argument
• Recall : is cons operator inserts element onto front
of a list

159.331               Prog Lang & Alg          20
• Function uniq accepts a sorted list and eliminates all but the
first occurrence of each item
uniq [ ] = [ ]                       ||escape hatch: empty list
uniq ( a: ( a: x) ) = uniq ( a : x )         || matches eg [3,3,…]
uniq ( a : x ) = a : uniq x                  || matches all other lists
• 2nd equation uses an advanced feature - that of specifying
the same variable (a) twice in the same pattern so this
matches eg [3,3,4] but not [3,4,5]
• If 2nd succeeds a recursive call is made with same list as
• If first two fail third is used also with recursive call but
159.331                     Prog Lang & Alg                       21
• Note that textual order of equations is significant
• (in uniq example 2nd and 3rd can succeed
simultaneously)
• May be preferable to add some condition to the
third pattern requiring its first two elements to be
different - matter of programming style
• Note also that uniq is polymorphic:
uniq [ 3, 3, 4, 6, 6, 6, 6, 7 ]              => [ 3, 4, 6, 7]
uniq [‘a’, ‘b’, ‘b’, ‘c’ ]                   => [‘a’, ‘b’, ‘c’ ]
• This approach is typical of functional
programming.
159.331                  Prog Lang & Alg                         22
Summary
•   Higher-Order functions
•   Currying
•   Strict semantics
•   Equations and pattern matching

• See Bal & Grune Chapter 4, Sebesta Chapter 15

• Next - application examples, and examples of
functional languages and summary.

159.331              Prog Lang & Alg          23

```
To top