Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 40

Chapter 9: Functional

Programming in a Typed
Language

Essence
What is the function that must be applied to
the initial machine state by accessing the
initial set of variables and combining them
in a specific ways in order to get an answer?
Languages that emphasize this view are
called functional languages

Essence
Program development proceeds by
developing functions from previously
developed function in order to build more
complex functions that manipulate the
initial set of data until the final function can
be used to compute and answer for the
initial data

Standard ML
ML is the working language of this chapter
because it best describes the topic of
functional programming.
The name of ML is an acronym for Meta
Language.
ML was initially designed for computerassisted reasoning.

Functional Programming
Precise definition is up to debate
pure functional programming - do not allow
side effects
Scheme (Lisp), ML are all impure, do allow side
effects
There are some pure, Haskell, Miranda
However when we compare programs written in the pure
and programs written in the pure part of Scheme, Lisp and
ML there is little difference

9.1 Exploring a List


Lists are considered to be the original data
structure of functional programming.
Most of the functions explore the structure
of the list.
Examples of these functions include:
APPEND FUNCTION
REVERSE FUNCTION

Operations on Lists
ML lists are written in between brackets and
separated by commas.
Example: [11, 23, 34] , [ ]

A list has the form of a::y. Where a is the


head of the list and y represents the tail of
the list.
Example: [7] => 7::[ ]
Example: [11,23,34] => 11::34

Functions for Lists


NULL (null)

Test for emptiness.

HEAD (hd)

Return the first


element.
Return all except the
first element.
Infix list constructor

TAIL (tl)
CONS (::)

Linear Functions on Lists


Most functions consider the elements of a list one
by one.
In other words, they behave as follows:
fun length(x) = if null (x) then 0
else 1 + length(tl(x))
(Recursive)

An empty list has a length of 0.


Length of a nonempty list x is 1 greater than the
length of the tail of x.

Definition of Append & Reverse


APPEND:
fun append(x, z) = if null(x) then z
else hd (x) :: append(tl(x), z)

REVERSE:
fun reverse(x, z) = if null(x) then z
else reverse(tl(x), hd(x) :: z)

Append Function
The append function uses the @ symbol
which combines two lists. For example:
append ([1,2], [3, 4, 5]) => [1, 2] @ [3, 4, 5]
=> [1, 2, 3, 4, 5]

Other examples:
append ([ ], z) => z
append (a::y, z) => a :: append (y, z)

Reverse Function
The function reverse can be used to reverse
a list. Following examples:
reverse([ ], z) => z
reverse(a::y) => reverse(y, a :: y)

The reverse function is related to the ML


function rev, which basically implements in
the same way. For example:
rev(x) => reverse(x, [ ])

Reverse/Append Phases
Linear functions like reverse and append
contain two different phases:
1. A winding in which the function examines
the tail of the list, and
2. an unwinding phase in which control
unwinds back to the beginning of the list.

Reverse/Append Phases
Example of the reverse winding phase:
reverse([2, 3, 4], [1]) => reverse([3, 4], [2, 1])
=> reverse([4], [3, 2, 1])
=> reverse([ ], [4, 3, 2, 1])
=> [4, 3, 2, 1]

Example of the append winding phase:


append([2, 3, 4], [1]) calls append([3, 4], [1])
append([3, 4], [1]) calls append([4], [1])
append([4], [1]) calls append([ ], [1])

Reverse/Append Functions
Here is the unwinding of the previous
function.
append([ ], [1]) => [1]
append([4], [1]) => [4, 1]
append([3, 4], [1]) => [3, 4, 1]
append([2, 3, 4], [1]) => [2, 3, 4, 1]

9.2 Function Declaration by


Cases
The format of function declarations is:
fun <name> <formal-parameter> = <body>

An example of this format is the successor


function:
fun succ n = n + 1

The application of a function f to an


argument x can be written either with
parentheses f(x), or without f x.

Function Applications
Function application has higher precedence than
the following operators:
<, <=, =, <>, >=, >
::, @
+, -, ^
*, /, div, mod

Examples:
3 * succ 4; => 3 * 5 => 15
3 * succ 4 :: [ ]; => 3 * list [5] => list [15]

Patterns
Functions with more than one argument can
be declared using the following syntax:
fun <name> <pattern> = <body>

A <pattern> has the form of an expression


made up of variables, constants, pairs of
tuples, and list constructors.
Examples:
(x,y), (a :: y), (x, _)

Patterns and Case Analysis


Patterns and case analysis give ML a readable
notation. Cases are separated by a vertical bar.
fun length([ ]) = 0
|
length(a :: y) = 1 + length(y)
The declaration of a function in ML can have the
following form.
fun f<pattern1> = <expression1>
|
f<pattern2> = <expression2>

Patterns and Case Analysis


The ML interpreter complains if the cases in a
function declaration are not complete, or in other
words taking each case into consideration.
Example:
fun head (a :: y) = a; [WARNING]
(Not a case for empty lists!!)
Other warnings come from misspellings or
repeated formals in patterns such as:
fun f(nul) = 0
null misspelled
strip(1, [1, 1, 2]) = 1 is repeated in formal

9.3 Functions as First-Class


Values
This section includes a small library with
useful functions such as map, remove_if,
and reduce.
The tools may use functions as arguments.
A function is called higher order if either
its arguments or its results are themselves
functions.

Mapping Functions
A filter is a function that copies a list, and
makes useful changes to the elements as
they are copied.
The idea behind the function map is for
each element a of a list, do something with
a and return a list of the results.
For example:
map square [1, 2, 3, 4] => [1, 4, 9, 16]

The Utility of Map


The beauty of functional programming lies in
the ability to combine functions in interesting
ways.
Examples use the following functions:
Square Multiply an integer argument by itself
First Return the first element of a pair
Second Return the second element of a pair.

Before defining new functions, we will consider a


short example involving the map.

The Utility of Map


Example:
hd [ [11, 12, 13, 14],
[21, 22, 23, 24],
[31, 32, 33, 34] ]; => [11, 12, 13, 14]
map hd [ [11, 12, 13, 14],
[21, 22, 23, 24],
[31, 32, 33, 34] ]; => [11, 21, 31]

Anonymous Functions
In ML, an anonymous function, a function without a
name, has the form
fn <formal-parameter> => <body>

Example:
fn x => x * 2

These functions are helpful for adapting existing


functions so they can be used together with tools like
map.
map (fn x => x*2) [1,2,3,4,5];
[2,4,6,8,10]

Selective Copying
The remove_if function is another higher
order function that removes elements from
lists if some condition holds.
It is used in the same fashion as map.
Example:
fun odd = (x mod 2) = 1
remove_if odd [0, 1, 2, 3, 4, 5];
=> [0, 2, 4]

Accumulate a Result
The reduce function accumulates a result
from a list.
Most of the time this function is used with a
few simple functions such as sum_all, add,
multiply, etc.
For example:
reduce add [1, 2, 3, 4, 5] 0;
=> 15

9.4 ML: Implicit Types


Even when ML checks its types at compile
time, ML expressions are surprising free of
type declarations.
This section will consider two aspects of
types in ML.
Inference
Polymorphism

Type Inference
ML refers types when the user has not specified
the type. For example:
3 * 4;
=> val it = 12 : int
(Since the 3 and 4 are integers the product yields an
integer)

The type of an expression can be specified by


writing
<expression> : <type>

Overloading yields an error. For example:


fun add (x, y) = x + y; => Error

Parametric Polymorphism
A polymorphic function can be applied to
arguments of more than one type.
We concentrate on parametric polymorphism,
a special kind of polymorphism, in which
type expressions are parameterized.
Example: alpha -> alpha
(with parameter alpha)

Parametric Polymorphism
Example:
fun length (nil) = 0
|

length (a :: y) = 1 + length (y);


=> fn : (alpha-> int)

Example:
length ([hello, world]);
=> 2 : int (remember the # in the list)
(Holds the strings as ints.)

9.5 Data Types


Datatype declarations in ML are useful for
defining types that correspond to data
structures.
Examples of data structures include binary
trees, arithmetic expressions, etc.

Value Constructors
A datatype in ML introduces a basic type as
a set of values. Here is an example of a
datatype direction.
datatype direction = north| south| east| west
=>
{ north, south, east, west }

These values become atomic; they are


constants with no components.

Value Constructors with


Parameters

A datatype declaration involves two parts.


1.
2.

A type name.
A set of value constructors for creating values of that
type.

Value Constructors can have parameters, as in


the following declaration of datatype bitree.
datatype bitree = leaf| nonleaf of bitree*bitree
In words, a value of type bitree is either the
constant leaf or it is constructed by applying
nonleaf to a pair of values of type bitree.

Binary Trees
Leaf

Nonleaf (leaf, leaf)

Nonleaf (nonleaf (leaf, leaf), leaf)

Nonleaf (leaf, nonleaf (leaf, leaf))

Operations on Constructed
Values
Patterns can be used to examine the
structure of a constructed value.
Example:
nonleaf ( leaf, nonleaf (leaf, leaf))
fun leafcount (leaf) = 1
|
leafcount (nonleaf (s,t)) = leafcount (s) +
leafcount (t);
=> 3 leaves

Differentiation: A Traditional
Example
Symbolic differentiation of expressions like
x*(x+y) is a standard example.
An expression is either a constant, variable,
sum, or a product. For example:
datatype expr = constant of int
| variable of string
| sum of expr *expr
| product of expr * expr;
val zero constant (0); (Declaration)
=> val zero = constant 0 : expr

Differentiation: A Traditional
Example
Example where d => derivative:
fun d x (constant_) = zero
(This statement reads the derivative of any
constant is zero.)

Polymorphic Datatypes
Lists are polymorphic. In other words, there can be
lists of integers, lists of strings, lists of type alpha, for
any type alpha.
Example of a datatype declaration would be:
datatype alpha List = Nil | Cons of alpha * (alpha List)

Example:
Nil : alpha List
(This statement reads that the value of Nil must
denote an empty list, where List is of alpha datatype.)

Functional Programming
Exception handling will be in a separate lecture
look at how little quilt is implemented in ML starting in
section 9.7
Do exercise 9.1 page 380. Remember use existing ML
functions to create these

You might also like