Functional Programming Languages - Lecture Slides | COP 4020, Study notes of Programming Languages

Material Type: Notes; Class: Programming Languages I; Subject: Computer Programming; University: University of Central Florida; Term: Spring 2006;

Typology: Study notes

Pre 2010

Uploaded on 11/08/2009

koofers-user-k4q
koofers-user-k4q 🇺🇸

5

(1)

9 documents

1 / 13

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Introduction
The functional programming language paradigm is based upon mathematical
function theory. A mathematical function is a mapping of members of a domain
set onto the members of a second set called the range set. The function yields
(or returns) an element of the range set.
y = f(x)
domain set range set
Figure 1 – A mathematical function.
A fundamental characteristic of mathematical functions is that the evaluation
order of the mapping expressions is controlled by recursion and conditional
expressions (composition of functions) rather than by sequencing and iterative
repetition which is common to imperative languages.
A purely functional language does not use variables or assignment statements.
A functional language should provide:
A set of primitive functions.
A set of functional forms.
A function application operation.
Structures for storing data.
Table 2 illustrates some of the primary differences between imperative
languages and functional languages.
Imperative Languages Functional Languages
Chapter 15 – Functional Programming Languages - 1
Functional Programming Languages – Chapter 15
x
y
pf3
pf4
pf5
pf8
pf9
pfa
pfd

Partial preview of the text

Download Functional Programming Languages - Lecture Slides | COP 4020 and more Study notes Programming Languages in PDF only on Docsity!

Introduction The functional programming language paradigm is based upon mathematical function theory. A mathematical function is a mapping of members of a domain set onto the members of a second set called the range set. The function yields (or returns) an element of the range set. y = f(x) domain set range set Figure 1 – A mathematical function. A fundamental characteristic of mathematical functions is that the evaluation order of the mapping expressions is controlled by recursion and conditional expressions (composition of functions) rather than by sequencing and iterative repetition which is common to imperative languages. A purely functional language does not use variables or assignment statements. A functional language should provide:  A set of primitive functions.  A set of functional forms.  A function application operation.  Structures for storing data. Table 2 illustrates some of the primary differences between imperative languages and functional languages. Imperative Languages Functional Languages

Functional Programming Languages – Chapter 15

x y

Programmers must deal with variables and the assignment of value. Programmers are not concerned with variables or assignment of value. Increased execution efficiency. Decreased execution efficiency. (See below.) Program construction is more laborious. Program construction is less laborious. It is a higher level of programming. Syntax is complex Simple syntactic structure Semantics are complex Semantics are simple Concurrent execution is difficult to design and utilize. Concurrency can be determined by the execution system. Less efficient on uni-processor machines, but may be more efficient on multi-processor machines. Table 2 – Comparison of imperative and functional languages. Another important characteristic of mathematical functions is that, because they have no side effects, they always return the same value given the same set of arguments. Side effects in programming languages are connected to variables which model memory locations. A mathematical function defines a value, rather than specifying a sequence of operations on values in memory to produce a value. Since there are no variables in functional languages (in the sense that there are variables in an imperative language), there can be no side effects. The functional model of programming languages (as well as the imperative model) grew out of the work undertaken by mathematicians Alan Turing, Alonzo Church, Stephen Kleene, and Emil Post, among others in the 1930s. Working independently, these individuals developed several very different formalizations of the notion of an algorithms, or effective procedure , based on automata, symbolic manipulation, recursive function definitions, and combinatorics. Over time these various formalizations were shown to be equally powerful; anything that could be computed in one could be computed in the others. This result led Church to conjecture that any intuitively appealing model of computing would be equally powerful as well; this conjecture is known as Church’s thesis. Turing’s model of computation was the Turing machine , an automaton reminiscent of a finite or pushdown automaton, but with the ability to access arbitrary cells of an unbounded storage “tape”. The Turing machine computes in an imperative way, by changing the values of cells in its tape, just as a high-level imperative program computes by changing the values of variables. Church’s model of computing is called the lambda calculus. It is based on the notion of parameterized expressions (with each parameter introduced by an occurrence of the letter  - hence the notation’s name). Lambda calculus was the inspiration for functional programming: one uses it to compute by substituting

There are many different functional forms, but the three illustrated in the textbook are representative of the various types. Composition form: h  f  g semantics: h(x) = f(g(x)) examples: let f(x)  x + x and g(x)  x * x h(3) = f(g(x)) = f(33) = f(9) = (9+9) = 18 let f(x)  x * x and g(x)  x + x h(2) = f(g(x)) = f(2+2) = f(4) = f(44) = 16 Construction form: [f, g, …, i] semantics: (f(x), g(x), …, i(x)] examples: let f(x)  x+x and g(x)  x*x f, g = (10, 25) let f(x)  x * x, g(x)  2 * x, and h(x)  x / 2 f, g, h = (16, 8, 2) Apply to All form:  semantics: apply each parameter in a parameter list to a single function to produce a list of values that is the result of the function. examples: let f(x)  x + x (f, (3, 5, 10, 7)) = (6, 10, 20, 14) let f(x)  x * x (f, (2, 4, 6)) = (4, 16, 36) A Lambda-Calculus Review

Lambda calculus has a small syntax consisting of only three constructs: variables, function application, and function creation. This makes it particularly well-suited for studying types in programming languages. Since its inception in the 1930’s (developed by Alonzo Church primarily as a tool for studying computation with functions), it has had a profound influence on the design and analysis of many programming languages. The general form of a -calculus expression is: x.M where x is the parameter and M is the body of the lambda function. In -calculus, functions are written next to their arguments, so f a represents the application of function f to argument a , as in sin  or log n. Examples The following are all -expressions: x.x - this is a function which takes a single argument and simply returns the value of that argument. x. x * x - this is a function which takes a single argument and returns the value of the argument multiplied by itself. (x. x * x (5)) - defined above - this function returns the value 25. (x. x * x) 5 – is also a frequently used syntax for -calculus expressions. Formulas like (x. x * x) 5 are called terms. A grammar for terms in the pure lambda calculus is given by: M ::= x | (M 1 M 2 ) | (x.M) Commonly, letters f, x, y, z denote variables and M, N, P, Q represent terms. A term is either a variable x , an application (M N) of function M to N, or an abstraction (x.M). In an applied lambda calculus, a constant c can be added as an option which represents values like integers and operations on data structures like lists. Thus c can stand for basic constants like true and nil as well as constant functions like + and first. The lambda calculi are therefore a family of languages for computation with functions. Equality of Lambda Calculus Terms

  1. free(x.M) = free(M) – {x} Rule 1 states that variable x is free in the term x. Rule 2 states that a variable is free in (M N) if it is either free in M or free in N. Rule 3 states that, with the exception of x, all other free variables of M are free in x.M. Example: In the term (y.z) (z.z), z is a free variable in the sub-term y.z because z is a free variable. The occurrence of x to the right of  in x.M is called a binding occurrence or simply a binding of x. All occurrences of x in x.M are bound within the scope of this binding. All unbound occurrences of a variable in a term are free. Each occurrence of a variable is either free or bound, it cannot be both. Example: The only occurrence of x in x.y is bound within its own scope. Consider the term: y.z.xz(y z) The following diagram the lines go from a binding to a bound occurrence.  y.  z. x z ( y z ) Recall that this term can also be written as: yz.xz(yz), which might make the above a bit easier to comprehend. Operations on Lambda Expressions -expressions have only one reduction operation which is substitution. If (FA) is a -expression where F = x.M, then A (an argument to the function) can be substituted for all free occurrences of x in M. This is written as: (x.M A)  M (it is also common to see this written as: {A / x} M). This operation is analogous to substituting an argument for a formal parameter in a function call. In general, substitution will replace variables by terms, thus the substitution of a term N for a variable x in M (written as: {N / x} M), proceeds according to the following two cases:
  2. If the free variables of N have no bound occurrences in M, then the term {N / x} M is formed by replacing all free occurrences of x in M by N.
  1. Otherwise, suppose that variable y is free in N and bound in M. Consistently replace the binding and corresponding bound occurrences of y in M by some new variable z. Repeat the renaming of bound variables in M until case 1 applies, then proceed as in case 1 above. The key-axiom of beta-equality is: (x.M) N = {N /x } M. Therefore, (x.x) u = u and (x.y) u = y. The -axiom is: (x.M) = z. {z / x} M – provided that z is not free in M. Therefore, x. x = y. y and xy. x = uv. u. Figure 2 summarizes the axioms and rules for beta-equality. Figure 2 – Axioms and rules for Beta-Equality The following are a few examples of the various equivalences that are possible in -calculus. (x.x y)  y [equivalent to: (x.x) y  y] (x. M) =) =   z. {z / x} M) = provided that z is not free in M) = (- axiom) (x.M) =) N ={N / x} M) = (- axiom) M) = =M) = (idempotence axiom) N M M N     (commutativity rule) M P M N N P       (transitivity rule) MN M N M M N N  ^    ^     (congruence rule) x.M x. M M M  ^  ^    (congruence rule)

In other words, if -expression M has the reductions M  P and M  Q, then there is a unique -expression R such that P  R and Q  R. R is then called the normal form for the value class represented by M. Parameter passing with -expressions There are two standard approaches to the reduction of -expressions: (1) reduce the outermost left term first, or (2) reduce the innermost left term first. Example Suppose we have the -expression (y.(yy) (x.(xx) a)). (1)Reduction by the outermost left term first: In this case the outermost left term is the entire -expression. (y.(yy) (x.(xx) a))  ((x.(xx) a) (x.(xx) a))  ((aa) (aa)) This technique substituted the function (x.(xx) a) for parameter y and evaluated this function for each occurrence of y (there are two such occurrences in this outermost function). Note: this is basically a "pass-by-name" type of parameter passing. (2)Reduction by the innermost left term first: In this case the innermost left term is (x.(xx) a). (y.(yy) (x.(xx) a))  (y.(yy) (aa))  ((aa) (aa)) This technique evaluated the constant (aa) before substituting for y. Thus the inner -expression (x.(xx) a) was evaluated (yielding the constant (aa)) first and this was then passed as the parameter to the outermost left term. Note: this is basically a "pass-by-value" type of parameter passing.

M) =

P Q

R

If a -expression has a normal form then reduction by the innermost left term first will find the normal form. Pass-by-name is a form of "lazy evaluation" - thus only expressions which are used in the final solution need to be evaluated. Pass-by-value, however, always evaluates arguments, so non-terminating arguments are evaluated even if they are not ultimately needed! This information can be utilized to create examples of terms that terminate via pass-by-name and do not terminate via pass-by-value. Need to compose a non-terminating -expression as an argument that is never referenced. Since we already know that the -expression: (x.(xx) x.(xx)) does not terminate since in the -expression: y.z, the parameter y is never referenced we can generate the following -expression: (y.z (x.(x x) x.(x x))) which has the normal form z , which is easily determined if pass-by-name is used, but represents a non-terminating -expression if pass-by-value is used. Modeling Predicate Calculus with Lambda Expressions Boolean Values Boolean values can be modeled as -expressions. Define True to be: x. y.x  xy.x. Define False to be: x. y.y  xy.y In this manner, True can be interpreted as: of a pair of values - pick the first. Similarly, False can be interpreted as: of a pair of values - pick the second. TRUE = x.y.x = x.y.x(T T) = xy.x (T T) = T [equivalent to (xy. x) T T  T] = x.y.x(T F) = xy.x (T F) = T [equivalent to (xy. x) T F  T] = x.y.x(F T) = xy.x (F T) = F [equivalent to (xy. x) F T  F] = x.y.x(F F) = xy.x (F F) = F [equivalent to (xy. x) F F  F] FALSE = x.y.y = x.y.y(T T) = xy.y (T T) = T [equivalent to (xy. y) T T  T] = x.y.y(T F) = xy.y (T F) = F [equivalent to (xy. y) T F  F] = x.y.y(F T) = xy.y (F T) = T [equivalent to (xy. y) F T  T] = x.y.y(F F) = xy.y (F F) = F [equivalent to (xy. y) F F  F] Given these definitions for True and False, the following properties hold: ((T P) Q)  P i.e., ((T P) Q)  ((xy.x P) Q)  (xy.P Q)  P

widespread use. Lisp has been far and away the most popular of the functional languages. APL is also considered a functional language, even though it makes heavy use of the assignment operation. Lisp is a versatile and powerful language, which has been both despised and loved by different programmers throughout the years. Lisp was originally designed for symbolic computations and list-processing applications. Both of these areas fall within the domain of artificial intelligence (AI). In AI, Lisp and some of its derivatives are still the dominant languages. Most of the existing expert systems were developed in Lisp, although this is one area in AI that has seen a fair amount of develop occur with logic based languages such as Prolog. Lisp dominates the areas of knowledge representation, machine learning, natural language processing, intelligent training systems, and the modeling of speech and vision. Lisp has also be successfully applied to areas outside of AI. The EMACS text editor is written in Lisp, so too is the symbolic mathematics system MAC-SYMA. There are three popular dialects of Lisp that you may run across. Scheme is perhaps the most popular of these followed by ML and Haskell. ML and Haskell have been most widely used in research and university teaching environments. Other functional languages include Sisal and Backus’s FP proposal.