Functional Programming

Download Report

Transcript Functional Programming

Functional Programming
Chapter 14
History of Functional Languages
• Lisp is the second oldest language
• Motivated by a need to do symbolic, rather
than numerical, manipulations.
• Common LISP and Scheme are the two
most popular dialects of the traditional
LISP.
• Haskell is a modern functional language
that adds strong typing to the more usual
features.
History/Characteristics
• LISt Processing
• The linked list is the major data structure
• Both programs and data can be
represented this way
– Programs are able to manipulate code just
like any other data
– Learning programs, …
Statement of Purpose
• “The Lisp language is primarily for
symbolic data processing. It has been
used for symbolic calculations in
differential and integral calculus, electrical
circuit design, mathematic logic, game
playing, and other fields of artificial
intelligence.”, 1965, from the LISP 1.5
Programmer’s Manual
Background: Functions
• A function f from a set X (the domain) to a
set Y (the range) maps each element x in
X to a unique element y in Y.
• For example, f(x) = x2 maps the set of real
numbers into the set of positive real
numbers (ignoring imaginary numbers).
Background: Functional
Composition
• If f is a function from X to Y and g is a function from
Y to Z, then (g ◦ f) (x) is a function from X to Z
defined as
(g ◦ f) (x) = g(f(x)), for all x in X
Simply put, it means to replace the x in g(x) with f(x).
• Example:
– f(x) = x2 + x
– g(x) = 2x + 1
– g ◦ f = 2(x2 + x) + 1
Overview
• Functional programming mirrors
mathematical functions:
– domain = input, range = output
– A computation maps inputs to outputs
• Variables are mathematical symbols; not
associated with memory locations.
– Compare to imperative programming
Overview
• Pure functional programming is state-free:
no assignment statements.
• Programs in pure functional languages
consist of composite functions; output of
each function is input to another.
• Today, most functional languages have
some imperative statements.
14.1 Functions and the Lambda
Calculus
• Typical function: Square(n) = n2
– funcName(args) = func-definition(expression)
• A function maps values from its domain to
values in its range.
•
Square : R  R maps from reals to reals
• A function is total if it is defined for all values of
its domain. Otherwise, it is partial. e.g., Square
is total.
Referential Transparency
• Referential transparency: as in mathematics, a
function’s result depends only upon the values of
its parameters and not on any previous
computation or the order of evaluation for its
arguments.
• In imperative programming results depend on
the parameter values, and may also change the
state (i.e., cause side effects):
x = x + y;
– lhs values versus rhs values
• Functional programs accept and return data, but
have no side effects.
Lambda Calculus
• The lambda calculus, invented in 1941, is
the foundation of functional programming
• Function specification without a name
– e.g., (  x . x2 ) represents the Square
function. Relate to mathematical notation
f(x) = x2
– ((  x . x2 )2): apply the function to a value,
similar to f(x) = x2 for x = 2
Lambda Calculus
• Is a general model of computation
– Can express anything that can be expressed by a
Turing machine; in other words, is Turing Complete
• An imperative language works by changing the
data store; a functional language works by
applying functions and returning values
– Lambda calculus models the latter approach
– Some practitioners claim that it is harder to make
mistakes while using this style of programming.
Pure Lambda Calculus*
• Any identifier is a lambda expression.
• If M and N are lambda expressions, then
the application of M to N, written (M N), is
a lambda expression
• An abstraction, written (x∙M), where x is
an identifier and M is a lambda
expression, is also a lambda expression.
BNFGrammar for  Expressions*
• LambdaExpression 
variable | ( M N) | (  variable ∙ M )
– M  LambdaExpression
– N  LambdaExpression
Examples*
• x
• (x ∙ x)
a variable is a lambda exp
 variable ∙ M is a lambda exp
(abstraction)
• ((x ∙ x) (y ∙ y)) (M N) is a lambda exp
(application)
• In ( x ∙ M), x is bound. Other variables in M are
free.
– A bound variable has the same name as a parameter
Bound Variables*
• Bound variables act like function
parameters in imperative languages, or
variables in math functions.
• They can be replaced (renamed)
consistently with any variable that is free in
M.
– Doesn’t change meaning of lambda
expression.
Properties of Lambda Exp*
• A substitution of expression N for all
occurrences of a variable x in M is written
M[x  N]. Examples:
Beta Reductions
(Function Application)
• A beta reduction (( x . M)N) of the lambda
expression ( x . M) is a substitution of all
bound occurrences of x in M by N. e.g.,
(( x . x2)5) = 52 M = x2 and N = 5
• Beta reduction represents a single function
application.
Evaluations
• Successive applications of betareductions:
• ((λy · ((λ x · xyz)a))b) ⇒ ((λy · ayz)b) ⇒
abz
or
• ((λy · ((λ x · xyz)a))b) ⇒ ((λx · xbz)a) ⇒
abz
• Evaluation (reduction) can be done in
either order
Pure v Applied Lambda Calculus
• Pure lambda calculus:
(( x . * x x)5) = (* 5 5)
(* and 5 have no meaning other than as symbols)
• Applied lambda calculus: (( x . * x x)5) = 25
• Functional languages = applied lambda calculus +
constant values + built-in functions (operators)
– e.g., (xyz) is a lambda expression; so is (x*y) or (*xy)
• Functional languages use prefix notation
When Are Arguments Evaluated?
• Eager evaluation = beginning of the call
– Advantage: efficiency
– Disadvantage: possible runtime errors
(if (= x 0) 1 (/ 1 x))
• Lazy evaluation = delaying argument
evaluation until the argument is needed.
– Advantage: flexibility and correctness
• Lisp and Scheme use eager evaluation,
Haskell uses lazy evaluation
Status of Functions
• In imperative and OO programming,
functions have different (lower) status than
variables.
• In functional programming, functions have
same status as variables; they are first-class
entities.
– They can be passed as arguments in a
call.
– They can transform other functions.
Example
• A function that operates on other functions is
called a functional form. e.g.,
g(f, [x1, x2, … ]) = [f(x1), f(x2), …], becomes
g(Square, [2, 3, 5]) = [4, 9, 25]
• Meaning: function g takes as parameters
another function and a list (sequence) of
values to which the parameter function is
applied.
14.2 Scheme
• A derivative of Lisp
• Our subset:
– omits assignments
– simulates looping via recursion
– simulates blocks via functional composition
• Scheme is Turing complete, even without
while statements
14.2.1 Expressions
• Cambridge prefix notation for all Scheme
expressions:
(f x1 x2 … xn)
•
•
•
•
•
e.g.,
(+ 2 2)
; evaluates to 4
(+(* 5 4)(-6 2)); means 5*4 +(6-2)
Note: Scheme comments begin with ;
Cambridge prefix allows operators to have an
arbitrary number of arguments.
The define Function
• Used to define global variables; e.g.
– (define f 120)
– define changes its environment but is not
equivalent to an assignment statement. It just
assigns a global name to a value.
• define can also be used for other
purposes, as we will see.
• setQ and setF are functions that
operate more like assignments; also set!
14.2.2 Expression Evaluation
• Three steps:
– replace names of symbols by their current
bindings.
– Evaluate lists as function calls in Cambridge
prefix.
A list is a set of elements enclosed in ( )
e.g., (* a 2)
• The first element in the list is treated as the
function
– Constants evaluate to themselves.
Examples
5
; evaluates to 5
Given the global definition (define f 120) then
f
; evaluates to 120
(+ f 5)
; evaluates to 125
(+ 5 2 9 13)
; evaluates to 29
#f
; predefined, false
#t
; predefined, true
5, #f, #t are constants, f is a bound
symbol
Lists as Function Calls
• (+ 5 2 9 13) ; evaluates to 29
but
• (+ (5 2 9 13)); an error
Scheme will try to evaluate the second list,
interpreting “5” as a function
• (f); error - f isn’t a function
Preventing Evaluation
(define colors (quote (red
yellow green)))
or
(define colors (‘ (red yellow
green)))
Quoting tells Scheme/LISP that the following
list is not to be evaluated.
Quoted Lists
(define x f)
; defines x as 120 (value of f)
(define x ‘f)
; defines x as the symbol f
(define color ‘red)
; color is defined to be red
(define color red)
; error: no definition of red
14.2.3 Lists
• A list is a series of expressions enclosed in
parentheses.
– Lists represent both functions and data.
– The empty list is written ().
– e.g., (0 2 4 6 8) is
a list of even
numbers.
– Here’s how it’s
stored:
What is a Cons?
• Each list node is a cons.
– A record with two fields: the car and the cdr:
car is the first field, cdr the second.
• Note that in the previous example the cdr
of the last node ( |8|nil| ) is nil.
– This is equivalent to the null pointer in C++
• The nil value can be represented as ( ),
which is the representation for an empty
list.
Dotted Lists
• In a dotted list the last cons has some value
other than nil as the value of the cdr field.
– “Dotted” lists are written (0 2 4 6 . 8) The last
node in the previous list would have been |6|8|
• Lists are assumed to end with the value ( )
which is implemented by null reference
• Some functions create dotted lists.
Structure of a
List in Scheme
(a)
Figure 14.1
(b)
Notice the difference
between the list with
nil as the last entry,
and the “dotted” list
shown in part b.
Representing a List with a List as
an Element
This represents
the list (a (b c))
a
nil
b
c
nil
Lists as Binary Trees
• Because each node in a Scheme list
consists of two pointers, internally the lists
are similar to binary trees.
• Recall;
– The links (pointers) are called the 'car' and the
'cdr'.
– A list node (cell) is also called a cons or a
pair.
List Functions
• cons: used to build lists
– Requires two arguments: an element and a list;
e.g.,
– (cons 8 ( )) ; gives the 1-element list (8)
– (cons 6 (cons 8( ))) ; gives the list (6 8)
– (cons 6 ‘(8)) ; also gives the list (6 8)
– (cons 4(cons 8 9)) ; gives the dotted list
; (4 8 . 9 ) since 9 is not a
; list
List Functions
• car: returns the first element (“head”) of a
list
• cdr: returns the tail of the list, which is
itself a list
• list: takes several arguments and returns a
list made up of those arguments
• append: takes two arguments and
concatenates the second to the end of the
first.
List Transforming Functions
• Suppose we write
(define evens ‘(0 2 4 6 8)).
Then:
(car evens)
; gives
(cdr evens)
; gives
(cons 1 (cdr evens))
; gives
(null? ‘())
; gives
0
(2 4 6 8)
(1 2 4 6 8)
#t, or true
More Examples
• (cdr(cdr evens)) ; (4 6 8)
• (car ‘(6 8) )
; 6
– The quote is necessary, otherwise Scheme would try
to treat “6” as a function.
– Since “evens” is already quoted, no need to
repeat.
• (cddr evens) is a shorthand notation for
(cdr (cdr evens)).
• Nest up to five cars and cdrs this way:
(cadr), (caar), (cddar), etc.
Equal
• The function equal? returns true if the
two objects have the same structure and
content.
(equal? 5 ‘(5)) ; gives #f, or false
(equal? 5 5)
; #t
(equal? ‘(1 2 3) ‘(1 (2 3)))
; returns false
List Building Functions
• list takes an arbitrary number of arguments and
creates a list; append takes two lists and
concatenates them:
– (append ‘(1 3 5) evens)
;gives(1 3 5 0 2 4 6 8)
– (append evens (list 3)
; gives (0 2 4 6 8 3)
– (list ‘(1 3 5) evens)
; gives ((1 3 5) (0 2 4 6 8))
– (list 1 2 3 4) ; gives (1 2 3 4)
– (list ‘evens ‘odds) ;gives (evens odds)
14.2.4 – Elementary Values
• Numbers: integers, rationals, and floating point
numbers
• Characters
• Functions
• Symbols
• Strings
• Boolean values #t and #f
• All values except #f and ( ) are interpreted as
true when used as a predicate.
Control Flow
(if test then-part)
(if test then-part else-part)
Example:
if (< x 0) (- 0 x)) ;returns –x if x<0
if (< x y) x y)
; returns the smaller of x, y
Control Flow
• The case statement is similar to a Java or
C++ switch statement:
• (case month
(( sep apr jun nov) 30)
((feb) 28)
(else 31) ; optional
)
• All cases take an unquoted list of
constants, except for the else.
Lisp conditional
• COND is the original Lisp conditional
statement and is sort of a cross between
an if and a case
• It takes a series of condition-result pairs
• (cond ( (< x 0) (-x) )
( (>= x 0) x )
)
Defining Functions
• define is also used to define functions;
according to the following syntax:
(define name (lambda (arguments) body))
or
(define (name arguments) body)
• From the former, one can see that Scheme
is an applied lambda calculus.
Examples
• (define (min x y) (if (< x y) x y))
to return the minimum of x and y
• (define (abs x)(if(< x 0)(- 0 x) x))
to find the absolute value of x
Recursive functions
• (define (factorial n)
(if(< n 1) 1 (* n factorial(-n 1)))
))
• (define (fun1 alist)
(if (null? alist) 0
(+ (car alist)(fun1(cdr alist)))
))
Built-in Functions
• length: returns the number of elements in
a list
– (length ‘(1 2 3 4)) ; returns 4
– (length ‘((1 2 3) (5 6 7) 8)) ; returns 3
• (define (length alist)
(if (null? alist) 0 (+ 1 (length (cdr alist)))
))
Built-in Functions
• member: tests whether an element is in a
list
(member 4 evens);returns (4 6 8)
(member 1 ‘(4 2)); returns ()
• If the element is in the list, return portion of
the list starting with that element, else
return the empty list.
Built in Functions
• Subst (substitute)
substitute its first argument for each
occurrence of its second argument in a list
which is the third argument.
(subst ‘x 2 ‘(1 2 3 2 1))
gives the list
(1 x 3 x 1)
How subst Works
(define (subst y x alist)
(if (null? alist) ‘())
(if (equal? x (car alist))
(cons y (subst y x (cdr alist)))
(cons (car alist) (subst y x (cdr alist)))
)))
Screen shot of list-building with the list function
4/28/10
Welcome to DrScheme, version 52.
Language: R4RS+.
> (list '(1 2 3) '(4 5 6))
((1 2 3) (4 5 6))
> (list '(1 2 3 . 5) (8 9))
procedure application: expected
procedure, given: 8; arguments were: 9
> (list '(1 2 . 5) '(6 7))
((1 2 . 5) (6 7))
>
Screen shot of list-building with the list function
4/28/10
> (append '(1 2 3) '(4 5 6))
(1 2 3 4 5 6)
> (append '(12.5) '(6 7))
(12.5 6 7)
>
Let Expressions
• Used to give a name to a value or
subexpression
• (let ((var1 expr1) (var2 expr2) … ) body)
• Simple example:
(let ((x 2) (y 3)))
(+x y))
Let Expressions
• Allows simplification of function definitions by
defining intermediate expressions. e.g.,
(define (subst y x alist)
(if (null? alist) ‘()
(let ((head (car alist)) (tail (cdr alist)))
(if (equal? x head)
(cons y (subst y x tail))
(cons head (subst y x tail))
)))
Functions as Parameters
• The mapcar function takes two
parameters: a function fun and a list
alist.
• mapcar applies the function to the list of
values, one at a time, and returns a list of
the results.
Functions as Parameters
(define (mapcar fun alist)
(if (null? alist) ‘()
(cons (fun (car alist))
(mapcar fun (cdr alist)))
))
E.g., if (define (square x) (* x x)) then
(mapcar square ‘(2 3 5 7 9))
returns
(4 9 25 49 81)
14.2.9 Symbolic Differentiation
• Symbolic Differentiation Rules
• Fig 14.2 d (c)  0
c is a constant
dx
d
(x)  1
dx
d
du dv
(u  v)  
u and v are funct ions ofx
dx
dx dx
d
du dv
(u  v)  
dx
dx dx
d
dv
du
(uv)  u  v
dx
dx
dx
 du
d
dv  2
(u /v)  v  u /v
 dx
dx
dx 
(define (diff x expr)
(if (not (list? expr))
(if (equal? x expr) 1 0)
(let ((u (cadr expr)) (v (caddr expr)))
(case (car expr)
((+) (list ‘+ (diff x u) (diff x v)))
((-) (list ‘- (diff x u) (diff x v)))
((*) (list ‘+ (list ‘* u (diff x v))
(list ‘* v (diff x u))))
((/) (list ‘div (list ‘- (list ‘* v (diff x u))
(list ‘* u (diff x v)))
(list ‘* u v)))
))))
Implementation of LISP
and its Dialects
• Usually implemented as an interpreted
language, although there are compiled forms.
• A LISP interpreter generally consists of:
– a memory manager
– collection of core functions implemented in compiled
form for speed
– a set of support functions implemented with the core
Syntax
• The syntax of Scheme (and LISP) is
simple and uniform.
• Most of the work in learning Scheme is
learning the names and effects of the
system functions that form the core of the
language.
Lisp is an Expression-Oriented
Language.
• Unlike most other languages, no distinction is
made between "expressions" and "statements"
• Code and data are written as expressions.
• When an expression is evaluated, it produces a
value (or list of values), which then can be
embedded into other expressions.
Common Core Functions
•
•
•
•
•
•
•
•
•
•
read & print
apply
eval
cons
car & cdr
setq or set! - a good one to know
define
NULL? & LIST?
COND
and all arithmetic functions
Using Scheme
• In Scheme, processing proceeds by typing
expressions into the Scheme
environment. After each expression is
entered, Scheme
– reads the expression,
– evaluates the expression to determine its
value, and
– prints the resulting value.
– This read-eval-print cycle forms the basis for
all processing within Scheme.
Dr. Scheme
•
To experiment with Scheme in the CS lab:
– From the Start button choose Programming
Languages/DrScheme/DrScheme
– Type the expression to be evaluated in the top
panel (or lower panel) of the window and click on
the Execute button.
– The results will appear in the lower panel.
Execute
Dr. Scheme
• You can also download the software and
install it at home.
• Here’s one source:
http://download.plt-scheme.org/drscheme/
Example (in the lower panel)
Welcome to DrScheme, version 52.
Language: R4RS+.
> (null? ())
#t
> (cadr '(a (b c) d e))
(b c)
>
How Lisp Processes the Code
• A Lisp program is expressed as a list or
set of nested lists.
• Lisp evaluates each list – it expects the
first element to be a function
List Evaluation
• If LISP attempts to evaluate a list which
does not begin with a function name (e.g.
(1 2 3) then execution will halt with an
error.
• This explains the need for the quoted list
which causes the interpreter to treat the
list as data only.
Memory Management in LISP
• Memory is organized into cells (or nodes).
• all cells are the same size, usually 2 words of
memory
• cells form a large pool of available storage,
chained together into the initial free list.
• cells are taken off the free list as needed to
build atoms, lists, etc.
Memory Management in Lisp
• Literal atoms may require several cells to
hold their definition (Remember the list
diagram)
• Each cell must be big enough to hold a
pointer to the next list element, and a
pointer to the current element value
Garbage Collection
• Evaluations in LISP take needed cells off
of the free list. Many results are
temporary and then are of no more use.
• Therefore, must have mechanism for
reclaiming space.
• Lisp was the first language to use
automatic garbage collection extensively
Another Lisp Quote
– Lisp has jokingly been called "the most
intelligent way to misuse a computer". I
think that description is a great compliment
because it transmits the full flavor of
liberation: it has assisted a number of our
most gifted fellow humans in thinking
previously impossible thoughts.
– — Edsger Dijkstra, CACM, 15:10