From software engineering point of view, a language without supporting persistent data objects might seem completely impractical.
The functional programming paradigm supports persistent data objects as a special component – functional data. The functional data model defines persistent data objects, attributes and relationships as so-called database functions. Database functions can be seamlessly integrated with ordinary functions mentioned above using construct operators.
1.1 Database Functions
Data Objects are called Database Entities or simply Entities in terminology of the Functional Data Model. All Entities must be declared as special functions that are devoid of parameters.
For example, the database schema dealing with three Entities - Customer, Product and Transaction where each transaction describes a shipment of a product to a customer, can be defined as follows:
CUSTOMER( ) ENTITY
PRODUCT( ) ENTITY
TRANSACTION( ) ENTITY
Note that two or more different entities within a functional database may have duplicate values of all data items (attributes). The Internal Key (IK) is conceptually a data item, whose value is automatically associated with each stored entity in the database. We can think of it as a unique internal identifier used inside a database to distinguish one entity from another. Each entity is assigned an internal key value when it is stored in the database for the first time. An entity retains a value of the internal key (even if the entity is modified) until the entity is finally deleted from the database.
as a function which produces a particular value of the internal key for each existing entity.
For instance, the function CUSTOMER( ) ENTITY might look as follows:
#1, Smith, . . .
#2, Hill, . . .
In analogy, all attributes of a particular entity must be also defined in the form of functions. For example, if the entity "CUSTOMER" is described with attributed C# (customer's number), CNAME (customer's name), CITY (city where the customer lives) and PHONE (customer's phone number), then such functions should be declared as follows:
Such function maps a particular value of the internal key into a corresponding value of the attribute.
For instance, the functions:
C#(CUSTOMER) integer and CNAME(CUSTOMER) string
might look as follows:
Normally, an information model consists of two main parts: entities and relationships. The mechanisms of the functional data model described so far do not suffice to cover relationships between entities which are, obviously, a very important part of an information model. Consider, for instance, the following relationships in the database being discussed.
The customer Smith ($C1) has bought the product VDU ($P1), this event is represented in the database by the entity TRANSACTION with internal key $T1. The customer Hill ($C2) has also bought the same product (see the entity TRANSACTION with internal key $T2). Such relationships between entities are described as database functions that are applied to entities and return entities as a result.
Functions of this kind transform an internal key of one entity into corresponding internal key of another one.
Thus, for the previously discussed example, the functions are as follows:
Hence, the functional data model defines a database schema as a set of database functions.
/* Definitions of entities */
CUSTOMER( ) ENTITY
PRODUCT( ) ENTITY
TRANSACTION( ) ENTITY
/* Definition of attributes */
QNT (TRANSACTION) INTEGER
/* Definition of relationships */
There exists a useful graphic notation for functional database schemas. This notation is known as a Data Structure Diagram. In accordance with the notation, each entity (i.e., a function which defines an entity) is depicted as a rectangle. The rectangle contains the name of the entity. All other functions are depicted as arrows. The arrow is directed to the resultant entity or data type; the arrow emanates from the symbol of entity which corresponds to parameters of the function.
In the functional data model, for each function f(s) t the inverse function Inv_f(t) s is also available.
For example, the inverse function INV_C#(integer) CUSTOMER maps values of the attribute C# into internal keys of the entity Customer.
Analogously, the inverse function INV_CNAME(STRING) CUSTOMER transforms a particular value of the attribute CNAME into a corresponding internal key of an entity CUSTOMER.
There also exists inverse functions which describe relationships between entities. For instance, the inverse function INV_CT(CUSTOMER) TRANSACTION transforms an internal key of the entity CUSTOMER into a corresponding internal key of the entity TRANSACTION.
The functional data model supports single-valued and multi-valued functions. All functions discussed so far are single-valued ones because they produce single value as a result. Multi-valued functions produce results which belong to a so-called bulk data type. The only bulk data type available in the functional data model is a list (i.e., sequential number of elements which can be lists or single values in turn). Hence, multi-valued functions are represented by list-valued functions in the functional data model.
For instance, the inverse function
is a list-valued function since it generally, produces a list of values as a result.
INV_PT($P1) [$T1, $T2] list of single values of internal keys.
Note that a single-valued function may be applied to a list (i.e., a list of values may be used as a parameter of single-valued function). In this case, the result of the function is also a list of values, because the function is considered to be applied sequentially to each element of the input list.
The type of a particular database function gives essential information about the semantics of a database.
For instance, if the function INV_C#(integer) CUSTOMER is defined as a single-valued one, then the attribute C# can be seen as an external key (i.e., duplicate values are not allowed).
In analogy, definition of the function CP(TRANSACTION) CUSTOMER as a single-valued function ensures that each entity "TRANSACTION" corresponds to exactly only one entity "CUSTOMER", and so on.
Thus, in order to distinguish types of certain functions, single-valued functions are represented by single-headed arrows () and multi-valued functions are represented by double-headed arrows (). If inverse function is not declared explicitly as a single-valued one, it is considered to be a multi-valued function (default option).
For instance, the functions INV_CNAME, INV_PT, INV_CT etc. are multi-valued ones and, hence, can be defined as follows:
Thus, a functional database system consists of the following components:
1. Database functions
2. Current state of the database functions defined as a collection of pairs
[Parameter] [Resultant Value]
1.2Working With Database Functions
Queries in the functional data model are also defined using of functions. Such a user-defined function is called a query function or data manipulation functions. In the most simple case, database functions can be just combined in order to build query functions.
For instance, the query
"Get names of customers from Paris" can be defined as the following composite function:
Suppose that a database is defined by means of two database functions:
CITY(CUSTOMER) string and CNAME(CUSTOMER) string
Suppose also that the functions looks as follows:
In this particular case, the query is evaluated as follows:
CNAME(($C2,$C4)) ["Hill", "Maier"]
Analogously, the query "Get names of customers who bought the product "CPU "" is defined in the form:
CNAME( CT( INV_PT(INV_PNAME("VDU") ) ) ) string
Suppose also that the database functions (i.e. the current database state) looks as follows:
Thus, the multi-valued function INV_PT returns the following lists:
INV_PT($P1) [$T1, $T3]
INV_PT($P2) [$T2, $T4]
In this case, the function is interpreted as follows:
CNAME([$C1,$C3]) ["Smith", "Johns"]
2Functional Paradigm: Summary
2.1Main Features of the Functional Paradigm
Thus, we can define main features of Functional Programming Paradigm as follows:
Functional programs do not use variables --- there is no state. Consequently, they cannot use assignments, since there is nothing to assign to.
There is no command sequence. First command makes no difference to the second since there is no state to mediate between them.
Functional programs can use functions in much more sophisticated ways. Functions can be treated in exactly the same way as simpler objects like integers: they can be passed to other functions as arguments and returned as results, and in general calculated with.
Instead of sequencing and looping, functional languages use recursive functions, i.e. functions that are defined in terms of themselves. By contrast, most traditional languages provide poor facilities in these areas. C allows some limited manipulation of functions via pointers, but does not allow one to create new functions dynamically. FORTRAN does not even support recursion at all.
2.2Benefits of the Paradigm
At first sight, a language without variables or sequencing might seem completely impractical. This impression cannot be dispelled simply by a few words here. But we hope that by studying the material above, readers have gained an appreciation of how it is possible to do a lot of interesting programming in the functional manner. Many features of imperative languages have arisen by a process of abstraction from typical computer hardware, from machine code to assemblers, to macro assemblers, and then to FORTRAN and beyond.
Perhaps the right approach is not to start from the hardware and work upwards, but to start with programming languages as an abstract notation for specifying algorithms, and then work down to the hardware (user-driven approach). Actually, this tendency can be detected in traditional languages too. Even FORTRAN allows arithmetical expressions to be written in the usual way.
The programmer is not burdened with the task of linearizing the evaluation of subexpressions and finding temporary storage for intermediate results. This suggests that the idea of developing programming languages quite different from the traditional imperative ones is certainly defensible. However, to emphasize that we are not merely proposing change for change's sake, we should say a few words about why we might prefer functional programs to imperative ones.
Functional programs correspond more directly to mathematical objects, and it is therefore easier to reason about them. In order to get a firm grip on exactly what programs mean, we might wish to assign an abstract mathematical meaning to a program or command --- this is the aim of denotational semantics. Functional programs may lend themselves well to parallel implementation, i.e. the computer can automatically farm out different subexpressions to different processors. At the same time, functional programs are not without their problems. Since they correspond less directly the the eventual execution in hardware, it can be difficult to reason about their exact usage of resources such as time and space.
Inputoutput is also difficult to incorporate neatly into a functional model, though there are ingenious techniques based on infinite sequences. It is up to readers to decide, after reading this book, on the merits of the functional style. We do not wish to enforce any ideologies, merely to point out that there are different ways of looking at programming, and that in the right situations, functional programming may have considerable merits. Most of our examples are chosen from areas that might loosely be described as `symbolic computation', for we believe that functional programs work well in such applications. However, as always one should select the most appropriate tool for the job. It may be that imperative programming, objectoriented programming or logic programming are more suited to certain tasks.
2.3Software Engineering and Functional Programming Paradigm
Re-usability: anyone that needs a particular functionality can use an appropriate function, without having to code the algorithm from scratch.
Specialization: one person can concentrate on writing a best possible function for a particular task while others look after other areas.
Upgradability: if a programmer comes up with a better way to implement a function then he/she simply replace the code within the function.
Obviously, the paradigm is best suited for the rapid prototyping model of software development.