Functional C
Total Page:16
File Type:pdf, Size:1020Kb
Functional C Pieter Hartel Henk Muller January 3, 1999 i Functional C Pieter Hartel Henk Muller University of Southampton University of Bristol Revision: 6.7 ii To Marijke Pieter To my family and other sources of inspiration Henk Revision: 6.7 c 1995,1996 Pieter Hartel & Henk Muller, all rights reserved. Preface The Computer Science Departments of many universities teach a functional lan- guage as the first programming language. Using a functional language with its high level of abstraction helps to emphasize the principles of programming. Func- tional programming is only one of the paradigms with which a student should be acquainted. Imperative, Concurrent, Object-Oriented, and Logic programming are also important. Depending on the problem to be solved, one of the paradigms will be chosen as the most natural paradigm for that problem. This book is the course material to teach a second paradigm: imperative pro- gramming, using C as the programming language. The book has been written so that it builds on the knowledge that the students have acquired during their first course on functional programming, using SML. The prerequisite of this book is that the principles of programming are already understood; this book does not specifically aim to teach `problem solving' or `programming'. This book aims to: ¡ Familiarise the reader with imperative programming as another way of imple- menting programs. The aim is to preserve the programming style, that is, the programmer thinks functionally while implementing an imperative pro- gram. ¡ Provide understanding of the differences between functional and imperative pro- gramming. Functional programming is a high level activity. The ordering of computations and the allocation of storage are automatic. Imperative pro- gramming, particularly in C, is a low level activity where the programmer controls both the ordering of computations and the allocation of storage. This makes imperative programming more difficult, but it offers the imperative programmer opportunities for optimisations that are not available to the func- tional programmer. ¡ Familiarise the reader with the syntax and semantics of ISO-C, especially the power of the language (at the same time stressing that power can kill). We visit all dark alleys of C, from void * to pointer arithmetic and assignments in expressions. On occasions, we use other languages (like C++ and Pascal) to illustrate concepts of imperative languages that are not present in C. C has been chosen because it is a de facto standard for imperative programming, and because its low level nature nicely contrasts with SML. Those who want to learn, for example, Modula-2 or Ada-95 afterwards should not find many difficulties. iii iv Preface ¡ Reinforce the principles of programming and problem solving. This is facilitated by the use of three different languages (mathematics, a functional language, and an imperative language). The fact that these widely differing languages have common aspects makes the idea that programming principles exist and that they are useful quite natural. ¡ Reinforce the principle of abstraction. Throughout the book we encourage the student to look for more abstract solutions, for example, by viewing the sig- nature of a function as an abstraction of its purpose, by using procedural ab- stractions (in particular higher order functions) early on, and by using data abstraction. ¡ Guide the student from specification and mathematics to implementation and software engineering. In the first chapters the emphasis is on writing correct functions and as we make progress the emphasis gradually shifts to trans- forming correct functions into efficient and reusable functions. Clean inter- faces are of paramount importance, and are sacrificed for better efficiency only as a last resort. Each problem in this book is solved in three steps: ¡ A specification of the problem is made. ¡ An appropriate algorithm is found to deliver solutions that satisfy the speci- fication. ¡ The algorithm is implemented as efficiently as possible. Throughout the book, the emphasis is on this third step. The language of mathematics is used to specify the problems. This includes the basics of set theory and logic. The student should have some familiarity with the calculi of sets, predicate logic, and propositional logic. This material is taught at most universities during a first course on discrete mathematics or formal logic. The appropriate algorithm is given in SML. SML is freely available for a range of platforms (PC's, UNIX work stations, Apple), and is therefore popular as a teach- ing language. As many functional languages are not too different from SML, an appendix gives a brief review of SML for those familiar with any of the other main stream functional languages, such as Miranda, Haskell, Clean, or Scheme. As the target language to implement solutions in an imperative style we have chosen C. The choice to use C and not C++ was a difficult one. Both languages are mainstream languages, and would therefore be suitable as the target language. We have chosen C because it more clearly exposes the low level programming. To illustrate this consider the mechanisms that the languages provide for call by refer- ence. In C, arguments must be explicitly passed as a pointer. The caller must pass the address, the callee must dereference the pointer. This in contrast with the call by reference mechanism of C++ (and Pascal and Modula-2). This explicit call by ref- erence is a didactical asset as it clearly exposes the model behind call by reference, and its dangers (in the form of unwanted aliases). Revision: 6.8 Preface v As this book is intended to be used in a first year course, only few assumptions were made about prior knowledge of the students. Reasoning about the correct- ness of programs requires proof skills, which students might not have acquired at this stage. Therefore we have confined all proofs to specially marked exercises. To distinguish the programming exercises from the exercises requiring a proof, we have marked the latter with an asterisk. We are confident that the book can be used without making a single proof. However we would recommend the students to go through the proofs on a second reading. The answers to one third of the ex- ercises are provided in Appendix A. The student should have an understanding of the basic principles of comput- ing. This would include base 2 arithmetic and the principles of operation of the von Neumann machine. A computer appreciation course would be most appro- priate to cover this material. The book contains examples from other areas of com- puter science, including data bases, computer graphics, the theory of program- ming languages, and computer architecture. These examples can be understood without prior knowledge of these areas. Acknowledgements The help and comments of Hugh Glaser, Andy Gravell, Laura Lafave, Denis Nicole, Peter Sestoft, and the anonymous referees have been important to us. The mate- rial of the book has undergone its first test in Southampton in 1995/1996. The first year Computer Science students of 1995, and in particular Jason Datt and Alex Walker have given us a lot of useful feedback. We have used a number of public domain software tools in the development of the book. The noweb literate programming tools of Norman Ramsey, the rail road diagramming tools from L. Rooijakkers, gpic by Brian Kernighan, TEX, LATEX, New Jersey SML, and the Gnu C compiler were particularly useful. Revision: 6.8 vi Preface Revision: 6.8 c 1995,1996 Pieter Hartel & Henk Muller, all rights reserved. Contents Preface iii 1 Introduction 1 1.1 The functional and the imperative paradigms . 1 1.1.1 The advantage of state . 3 1.1.2 The advantage of pure functions . 3 1.1.3 Idiomatic building blocks in C . 3 1.2 Guide to the book . 4 2 Functions and numbers 7 2.1 A model of computation . 7 2.1.1 A computational model for SML programs . 8 2.1.2 A computational model for C programs . 9 2.1.3 Compiling and executing a C program . 10 2.2 Elementary functions . 10 2.2.1 The header of a C function, types and identifiers . 14 2.2.2 The body of a C function and its behaviour . 15 2.2.3 The execution of a C program . 17 2.2.4 Integers . 18 2.2.5 Logical operators . 19 2.2.6 Defining a type for Booleans, typedef and enum . 20 2.3 Characters, pattern matching, partial functions . 21 2.3.1 Implementing pattern matching in C . 22 2.3.2 Partial functions . 26 2.3.3 Differences and similarities between characters and integers . 27 2.4 Real numbers . 29 2.4.1 Coercions of integers and floating point numbers . 32 2.5 Functions as arguments . 34 2.5.1 Sums . 34 2.5.2 Products . 37 2.5.3 An extended example of higher order functions: bisection . 39 2.6 Summary . 44 2.7 Further exercises . 47 vii viii CONTENTS 3 Loops 51 3.1 A model of the store . 51 3.2 Local variable declarations and assignments . 53 3.3 While loops . 57 3.3.1 Single argument tail recursion . 61 3.3.2 Multiple argument tail recursion . 64 3.3.3 Non-tail recursion: factorial . 68 3.3.4 More on assignments . 73 3.3.5 Breaking out of while-loops . 75 3.4 For loops . 79 3.4.1 Factorial using a for-loop . 83 3.4.2 Folding from the right . 86 3.5 Generalizing loops and control structures . 88 3.5.1 Combining foldl with map: sum of squares . 89 3.5.2 Combining foldl with filter: perfect numbers . 91 3.5.3 Nested for statements . 95 3.6 Summary . 96 3.7 Further exercises . 98 4 Structs and Unions 101 4.1 Structs .