







Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Material Type: Notes; Class: Programming Languages I; Subject: Computer Programming; University: University of Central Florida; Term: Spring 2006;
Typology: Study notes
1 / 13
This page cannot be seen from the preview
Don't miss anything!








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
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
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.
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.