To save content items to your account,
please confirm that you agree to abide by our usage policies.
If this is the first time you use this feature, you will be asked to authorise Cambridge Core to connect with your account.
Find out more about saving content to .
To save content items to your Kindle, first ensure no-reply@cambridge.org
is added to your Approved Personal Document E-mail List under your Personal Document Settings
on the Manage Your Content and Devices page of your Amazon account. Then enter the ‘name’ part
of your Kindle email address below.
Find out more about saving to your Kindle.
Note you can select to save to either the @free.kindle.com or @kindle.com variations.
‘@free.kindle.com’ emails are free but can only be saved to your device when it is connected to wi-fi.
‘@kindle.com’ emails can be delivered even when you are not connected to wi-fi, but note that service fees apply.
From clarity to efficiency: systematic program design
At the center of computer science, there are two major concerns of study: what to compute, and how to compute efficiently. Problem solving involves going from clear specifications for “what” to efficient implementations for “how”. Unfortunately, there is generally a conflict between clarity and efficiency, because clear specifications usually correspond to straightforward implementations, not at all efficient, whereas efficient implementations are usually sophisticated, not at all clear. What is needed is a general and systematic method to go from clear specifications to efficient implementations.
We give example problems from various application domains and discuss the challenges that lead to the need for a general and systematic method. The example problems are for database queries, hardware design, image processing, string processing, graph analysis, security policy frameworks, program analysis and verification, and mining semi-structured data. The challenges are to ensure correctness and efficiency of developed programs and to reduce costs of development and maintenance.
Example problems and application domains
Database queries. Database queries matter to our everyday life, because databases are used in many important day-to-day applications. Consider an example where data about professors, courses, books, and students are stored, and we want to find all professor-course pairs where the professor uses any of his own books as the textbook for the course and any of his own students as the teaching assistant for the course.
The efficiency of a program is measured in terms of its memory requirements and its running time. In this chapter we shall introduce the concepts stack and heap because a basic understanding of these concepts is necessary in order to understand the memory management of the system, including the garbage collection.
Furthermore, we shall study techniques that in many cases can be used to improve the efficiency of a given function, where the idea is to search for a more general function, whose declaration has a certain form called iterative or tail recursive. Two techniques for deriving tail-recursive functions will be presented: One is based on using accumulating parameters and the other is based on the concept of a continuation, that represents the rest of the computation. The continuation-based technique is generally applicable. The technique using accumulating parameters applies in certain cases only, but when applicable it usually gives the best results. We give examples showing the usefulness of these programming techniques.
We relate the notion of iterative function to while loops and provide examples showing that tail-recursive programs are in fact running faster than the corresponding programs using while loops.
The techniques for deriving tail-recursive functions are useful programming techniques that often can be used to obtain performance gains. The techniques do not replace a conscious choice of good algorithms and data structures. For a systematic study of efficient algorithms, we refer to textbooks on “Algorithms and Data Structures.”
The purpose of this book is to introduce a wide range of readers – from the professional programmer to the computer science student – to the rich world of functional programming using the F# programming language. The book is intended as the textbook in a course on functional programming and aims at showing the role of functional programming in a wide spectrum of applications ranging from computer science examples over database examples to systems that engage in a dialogue with a user.
Why functional programming u sing F#?
Functional programming languages have existed in academia for more than a quarter of a century, starting with the untyped Lisp language, followed by strongly typed languages like Haskell and Standard ML.
The penetration of functional languages to the software industry has, nevertheless, been surprisingly slow. The reason is probably lack of support of functional languages by commercial software development platforms, and software development managers are reluctant to base software development on languages living in a non-commercial environment.
This state of affairs has been changed completely by the appearance of F#, an open-source, full-blown functional language integrated in the Visual Studio development platform and with access to all features in the .NET program library.
Processing text files containing structured data is a common problem in programming – you may just think of analysing any kind of textual data generated by electronic equipment or retrieved data from the web.
In this chapter we show how such programs can be made in a systematic and elegant way using F# and the .NET library. Data are extracted from text files using functions from the RegularExpressions library. The data processing of the extracted data is done with a systematic use of F# collections types list <′a>, Map <′a,′b> and Set<′a>. Easy access from F# programs to the extensive text processing features of the .NET library is given in a special TextProcessing library that can be copied from the home page of the book. The chapter centers on a real-world example illustrating the techniques.
Time performance of programs is always a problem, even with todays very fast computers. Poor performance of text processing programs is often caused by operations on very long strings. The method in this chapter uses three strategies to avoid using very long strings:
1. Text input is in most cases read and processed in small pieces (one or a few lines).
2. Text is generated and written in small pieces.
3. Large amounts of internal program data are stored in many small pieces in F# collections like list, set or map.
Throughout the book we have used programs from the F# core library and from the .NET library, and we have seen that programs from these libraries are reused in many different applications. In this chapter we show how the user can make own libraries by means of modules consisting of signature and implementation files. The implementation file contains the declarations of the entities in the library while the signature file specifies the user's interface to the library.
Overloaded operators are defined by adding augmentations to type definitions. Type augmentations can also be used to customize the equality and comparison operators and the string conversion function. Libraries with polymorphic types are obtained by using signatures containing type variables.
These features of the module system are illustrated by small examples: plane geometric vectors and queues of values with arbitrary type. The last part of the chapter illustrates the module system by a larger example of piecewise linear plane curves. The curve library is used to describe the recursively defined family of Hilbert curves, and these curves are shown in a window using the .NET library. The theme of an exercise is a picture library used to describe families of recursively defined pictures like Escher's fishes.
This chapter is about programs where the dynamic allocation of computer resources like processor time and memory becomes an issue. We consider two different kinds of programs together with programming constructs to obtain the wanted management of computer resources:
1. Asynchronous, reactive programs spending most of the wall-clock time awaiting a request or a response from an external agent. A crucial problem for such a program is to minimize the resource demand while the program is waiting.
2. Parallel programs exploiting the multi-core processor of the computer by performing different parts of the computation concurrently on different cores.
The construction of asynchronous and parallel programs is based on the hardware features in the computer and software features in system software as described in Sections 13.1 and 13.2. Section 13.3 addresses common challenges and pitfalls in parallel programming. Section 13.4 describes the async computation expression and illustrates its use by some simple examples. Section 13.5 describes how asynchronous computations can be used to make reactive, asynchronous programs with a very low resource demand. Section 13.6 describes some of the library functions for parallel programming and their use in achieving computations executing concurrently on several cores.
A computation expression of F# provides the means to express a specific kind of computations in a way where low-level details are hidden and only visible through the use of special syntactic constructs like yield, let!, return, etc. These constructs are not part of the normal F# syntax and are only allowed inside computation expressions. Each kind of computation expression is defined by a computation builder object that contains the meaning of the special constructs.
A computation expression ce belonging to the builder object comp appears in the F# program in a construct of the form:
comp {ce}
This construct is an expression that evaluates to a value called a computation.
We have already seen examples of computation expressions in the form of sequence expressions with builder object seq (cf. Table 11.2) and query expressions with builder object query (cf. Section 11.8). The sequence computation expressions allow us to define computations on sequences without having to bother about the laziness and other implementation details, and the query expressions allow you to make database queries. In Chapter 13 we introduce asynchronous computation expressions with builder object async where you can define asynchronous computations without having to bother about low-level details in the current state of the system. The seq, query and async computation expressions are parts of F#.
In this chapter we will introduce some of the main concepts of functional programming languages. In particular we will introduce the concepts of value, expression, declaration, recursive function and type. Furthermore, to explain the meaning of programs we will introduce the notions: binding, environment and evaluation of expressions.
The purpose of the chapter is to acquaint the reader with these concepts, in order to address interesting problems from the very beginning. The reader will obtain a thorough knowledge of these concepts and skills in applying them as we elaborate on them through-out this book.
There is support of both compilation of F# programs to executable code and the execution of programs in an interactive mode. The programs in this book are usually illustrated by the use of the interactive mode.
The interface of the interactive F# compiler is very advanced as, for example, structured values like tuples, lists, trees and functions can be communicated directly between the user and the system without any conversions. Thus, it is very easy to experiment with programs and program designs and this allows us to focus on the main structures of programs and program designs, that is, the core of programming, as input and output of structured values can be handled by the F# system.
The purpose of this chapter is to illustrate the use of values of basic types: numbers, characters, truth values and strings by means of some examples. The concepts of operator overloading and type inference are explained. Furthermore, the chapter contains a gentle introduction to higher-order functions. It is explained how to declare operators, and the concepts of equality and ordering in F# are introduced. After reading the chapter the reader should be able to construct simple programs using numbers, characters, strings and truth values.
Numbers. Truth values. The unit type
From mathematics we know the set of natural numbers as a subset of the set of integers, which again is a subset of the rational numbers (i.e., fractions), and so on. In F#, however, the set of values with the type: int, for the integers, is considered to be disjoint from the set of values with the type: float, for floating-point numbers, that is, the part of the real numbers that are representable in the computer. The reason is that the encodings of integer and float values in the computer are different, and that the computer has different machine instructions for adding integer values and for adding float values, for example.
Tuples, records and tagged values are compound values obtained by combining values of other types. Tuples are used in expressing “functions of several variables” where the argument is a tuple, and in expressing functions where the result is a tuple. The components in a record are identified by special identifiers called labels. Tagged values are used when we group together values of different kinds to form a single set of values. Tuples, records and tagged values are treated as “first-class citizens” in F#: They can enter into expressions and the value of an expression can be a tuple, a record or a tagged value. Functions on tuples, records or tagged values can be defined by use of patterns.
Tuples
An ordered collection of n values (v1, v2,…,vn), where n > 1, is called an n-tuple. Examples of n-tuples are:
(10, true);;
val it : int * bool = (10, true)
((“abc”,1),–3);;
val it : (string * int) * int = ((“abc”, 1), –3)
A 2-tuple like (10,true) is also called a pair. The last example shows that a pair, for example, ((“abc”,1),–3), can have a component that is again a pair (“abc”,1). In general, tuples can have arbitrary values as components. A 3-tuple is called a triple and a 4-tupleis called a quadruple. An expression like (true) is not a tuple but just the expression true enclosed in brackets, so there is no concept of 1-tuple. The symbol () denotes the only value of type unit (cf. Page 23).
Functional languages make it easy to express standard recursion patterns in the form of higher-order functions. A collection of such higher-order functions on lists, for example, provides a powerful library where many recursive functions can be obtained directly by application of higher-order library functions. This has two important consequences:
1. The functions in the library correspond to natural abstract concepts and conscious use of them supports high-level program design, and
2. these functions support code reuse because you can make many functions simply by applying library functions.
In this chapter we shall study libraries for lists, sets and maps, which are parts of the collection library of F#. This part of the collection library is studied together since:
It constitutes the immutable part of the collection library. The list, set and map collections are finite collections programmed in a functional style.
There are many similarities in the corresponding library functions.
This chapter is a natural extension of Chapter 4 since many of the patterns introduced in that chapter correspond to higher-order functions for lists and since more natural program designs can be given for the two examples in Section 4.6 using sets and maps.
We will focus on the main concepts and applications in this book, and will deliberately not cover the complete collection library of F#. The functions of the collection library do also apply to (mutable) arrays. We address this part in Section 8.10.
This appendix provides complete programs of the keyword program from the Chapter 10. It consists of
a section introducing the basic HTML concepts,
a section containing the complete IndexGen program, and
a section containing the complete NextLevelRefs program.
The remaining program for the keyword example: MakeWebCat, appears in Table 10.19. The source can also be found on the homepage of the book.
Web source files
The source of a web-page is a file encoded in the HTML (Hyper Text Mark-up Language) format. This section gives a brief introduction to HTML using the library documentation web-page as an example.
An HTML file is an ordinary text file using a special syntax. Certain characters like <, >, & and “ are delimiters defining the syntactical structure. The file consists of elements of the form <…> intermixed with text to be displayed. The following construction will for instance make a button with a link to a web-page: