Chapter 9: Functional Programming in A Typed Language
Chapter 9: Functional Programming in A Typed Language
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
Operations on Lists
ML lists are written in between brackets and
separated by commas.
Example: [11, 23, 34] , [ ]
HEAD (hd)
TAIL (tl)
CONS (::)
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)
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]
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]
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>
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]
Anonymous Functions
In ML, an anonymous function, a function without a
name, has the form
fn <formal-parameter> => <body>
Example:
fn x => x * 2
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
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)
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
|
Example:
length ([hello, world]);
=> 2 : int (remember the # in the list)
(Holds the strings as ints.)
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 }
A type name.
A set of value constructors for creating values of that
type.
Binary Trees
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