Contents   Next

THE HASKELL SCHOOL OF EXPRESSION

Functional programming is a programming style that emphasizes the use of functions (in contrast to object-oriented programming, which emphasizes the use of objects). It has become popular in recent years because of its simplicity, conciseness, and clarity. This book teaches functional programming using Haskell, the most popular purely functional language. The emphasis is on functional programming as a way of thinking and problem solving, using Haskell as a vehicle for expressing solutions. Rather than using conventional - arguably boring - examples from mathematics, which are commonly found in other programming language books, this tutorial uses examples drawn from multimedia applications, including graphics, animation, and computer music, thus rewarding the reader with working programs for inherently more interesting applications. The author also teaches how to reason about functional programs, using a very simple process of calculation.

Aimed at both beginning and advanced programmers, this tutorial begins with a gentle introduction to functional programming, including basic ideas such as values, types, pattern matching, recursion, higher-order functions, data structures, polymorphism, abstraction, lazy evaluation, and proof by calculation. It then moves rapidly on to more advanced topics, such as infinite data structures, type classes, higher-order types, IO, monads, and inductive proofs. Details about programming in Haskell are presented in boxes throughout the text for easy reference.

Paul Hudak is Professor of Computer Science at Yale University. He was instrumental in organizing and chairing the Haskell Committee, an international group of computer scientists who designed Haskell, a nonstrict, pure functional programming language. He is a cofounder and editor of the Journal of Functional Programming. He has published over 100 papers on the design and application of programming languages.

Hudak believes that programming languages should be pushed further in the direction of high-level abstractions, in which the programmer says less about the details of a computation and more about the problem specification itself. At the same time, he recognizes the need for smart compilation techniques to make such languages practical. His most recent interest is in applying these principles to multimedia technology, including computer music, graphics and animation, and robotics.

The Haskell School of Expression
LEARNING FUNCTIONAL PROGRAMMING THROUGH MULTIMEDIA


PAUL HUDAK
Yale University


CAMBRIDGE UNIVERSITY PRESS
Cambridge, New York, Melbourne, Madrid, Cape Town, Singapore, Sao Paulo

Cambridge University Press
32 Avenue of the Americas, New York, NY 10013-2473, USA

Information on this title: www.cambridge.org/9780521643382

© Cambridge University Press 2000

This publication is in copyright. Subject to statutory exception
and to the provisions of relevant collective licensing
agreements, no reproduction of any part may take place
without the written permission of Cambridge University Press.

First published 2000
8th printing 2007

Printed in the United States of America

A catalog record for this publication is available from the British Library.

Library of Congress Cataloging in Publication Data

Hudak, Paul.
The Haskell school of expression: learning functional programming through
multimedia / Paul Hudak.
p. cm.
ISBN 0-521-64338-4 (hardback)-ISBN 0-521-64408-9 (pbk.)
1. Functional programming (Computer science) 2. Multimedia systems. I. Title.
QA76.62 H83 2000
005.1'14 21-dc21   99-045529

ISBN 978-0-521-64338-2 hardback
ISBN 978-0-521-64408-2 paperback

Cambridge University Press has no responsibility for
the persistence or accuracy of URLs for external or
third-party Internet Web sites referred to in this publication
and does not guarantee that any content on such
Web sites is, or will remain, accurate or appropriate.
This book is dedicated to
Cathy, Cristina, Jennifer, and Rusty
Contents
Preface
1. Problem Solving, Programming, and Calculation
1.1. Computation by Calculation in Haskell
1.2. Expressions, Values, and Types
1.3. Function Types and Type Signatures
1.4. Abstraction, Abstraction, Abstraction
1.4.1. Naming
1.4.2. Functional Abstraction
1.4.3. Data Abstraction
1.5. Code Reuse and Modularity
1.6. Beware of Programming with Numbers
2. A Module of Shapes: Part I
2.1. Geometric Shapes
2.2. Areas of Shapes
2.3. Cleaning Up
3. Simple Graphics
3.1. Basic Input/Output
3.2. Graphics Windows
3.3. Drawing Graphics Other Than Text
3.4. Some Examples
4. Shapes II: Drawing Shapes
4.1. Dealing With Different Coordinate Systems
4.2. Converting Shapes to Graphics
4.3. Some Examples
4.4. In Retrospect
5. Polymorphic and Higher-Order Functions
5.1. Polymorphic Types
5.2. Abstraction Over Recursive Definitions
5.2.1. Map is Polymorphic
5.2.2. Using map
5.3. Append
5.3.1. The Efficiency and Fixity of Append
5.4. Fold
5.4.1. Haskell's Folds
5.4.2. Why Two Folds?
5.5. A Final Example: Reverse
5.6. Errors
6. Shapes III: Perimeters of Shapes
6.1. Perimeters of Shapes
7. Trees
7.1. A Tree Data Type
7.2. Operations on Trees
7.3. Arithmetic Expressions
8. A Module of Regions
8.1. The Region Data Type
8.2. The Meaning of Shapes and Regions
8.2.1. The Meaning of Shapes
8.2.2. The Encoding of the Meaning of Shapes
8.2.3. The Meaning of Regions
8.2.4. The Encoding of the Meaning of Regions
8.3. Algebraic Properties of Regions
8.4. In Retrospect
9. More About Higher-Order Functions
9.1. Currying
9.2. Sections
9.3. Anonymous Functions
9.4. Function Composition
10. Drawing Regions
10.1. The Picture Data Type
10.2. Drawing Pictures
10.3. Drawing Regions
10.3.1. From Regions to Graphics Regions: First Attempt
10.3.2. From Regions to Graphics Regions: Second Attempt
10.3.3. Translating Shapes into Graphics Regions
10.3.4. Examples
10.4. User Interaction
10.5. Putting it all Together
10.5.1. Examples
11. Proof by Induction
11.1. Induction and Recursion
11.2. Examples of List Induction
11.2.1. Proving Function Equivalences
11.3. Useful Properties on Lists
11.3.1. Function Strictness
11.4. Induction on Other Data Types
11.4.1. A More Efficient Exponentiation Function
12. Qualified Types
12.1. Equality
12.2. Defining Your Own Type Classes
12.3. Inheritance
12.4. Haskell's Standard Type Classes
12.5. Derived Instances
12.6. Reasoning With Type Classes
13. A Module of Simple Animations
13.1. What is an Animation?
13.2. Representing an Animation
13.3. An Animator
13.4. Fun With Type Classes
13.4.1. Rising to the Level of Animations
13.4.2. Type Classes to the Rescue
13.4.3. Defining New Type Classes for Behaviors
13.5. Lifting to the Limit
13.6. Time Transformation
13.7. A Final Example: A Kaleidoscope Program
14. Programming With Streams
14.1. Lazy Evaluation
14.2. Recursive Streams
14.3. Stream Diagrams
14.4. Lazy Patterns
14.5. Memoization
14.6. Inductive Properties of Infinite Lists
15. A Module of Reactive Animations
15.1. FAL by Example
15.1.1. Basic Reactivity
15.1.2. Event Choice
15.1.3. Recursive Event Processing
15.1.4. Events with Data
15.1.5. Snapshot
15.1.6. Boolean Events
15.1.7. Integration
15.2. Implementing FAL
15.2.1. An Implementation Strategy
15.2.2. Incremental Sampling
15.2.3. Final Refinements
15.2.4. Representing Events
15.3. The Implementation
15.3.1. Behaviors
15.3.2. Events
15.3.3. An Example
15.4. Extensions
15.4.1. Variations on switch
15.4.2. Mouse Motion
15.5. Paddleball in Twenty Lines
16. Communicating With the Outside World
16.1. Files, Channels, and Handles
16.1.1. Why Use Handles?
16.1.2. Channels
16.2. Exception Handling
16.3. First-Class Channels and Concurrency
17. Rendering Reactive Animations
17.1. Preliminaries
17.2. Reactimate
17.3. Window User
18. Higher-Order Types
18.1. The Functor Class
18.2. The Monad Class
18.2.1. Other Instances of Monad
18.2.2. Other Monadic Operations
18.3. The MonadPlus Class
18.4. State Monads
18.5. Type Class Type Errors
19. An Imperative Robot Language
19.1. IRL by Example
19.2. Robot is a State Monad
19.3. The Implementation of IRL Commands
19.3.1. Robot Orientation
19.3.2. Using the Pen
19.3.3. Playing With Coins
19.3.4. Logic and Control
19.4. All the World is a Grid
19.5. Robot Graphics
19.6. Putting it all Together
20. Functional Music Composition
20.1. The Music Data Type
20.2. Higher-Level Constructions
20.2.1. Lines and Chords
20.2.2. Delay and Repeat
20.2.3. Polyrhythms
20.2.4. Determining Duration
20.2.5. Reversing Musical Structure
20.2.6. Truncating Parallel Composition
20.2.7. Trills
20.2.8. Percussion
20.3. A Couple of Final Examples
20.3.1. Cascades
20.3.2. Self-Similar (Fractal) Music
21. Interpreting Functional Music
21.1. Interpreting Music: A Performance
21.2. An Algebra of Music
22. From Performance to MIDI
22.1. An Introduction to MIDI
22.2. The Conversion Process
22.3. Putting It All Together
23. A Tour of the PreludeList Module
23.1. The PreludeList Module
23.2. Simple List Selector Functions
23.3. Index-Based Selector Functions
23.4. Predicate-Based Selector Functions
23.5. Fold-like Functions
23.6. List Generators
23.7. String-Based Functions
23.8. Boolean List Functions
23.9. List Membership Functions
23.10. Arithmetic on Lists
23.11. List Combining Functions
24. A Tour of Haskell's Standard Type Classes
24.1. The Ordered Class
24.2. The Enumeration Class
24.3. The Bounded Class
24.4. The Show Class
24.5. The Read Class
24.6. The Index Class
24.7. The Numeric Classes
A. Built-in Types Are Not Special
B. Pattern-Matching Details
Bibliography
Index
Preface

The first high-level languages developed for general purpose programming were Fortran (Backus, 1978) and Lisp (McCarthy, 1978), developed in the late 1950s by John Backus and John McCarthy, respectively. From Fortran grew many of today's modern imperative languages, most of which did not improve significantly on the fundamental ideas found in the language Algol (de Morgan, Hill and Wichmann, 1976), which shortly followed Fortran. The Lisp family was less fecund, perhaps because it was so far ahead of its time, but was the seed for the family of functional languages about which this textbook was written. The most radical in this class of languages is probably Haskell originally designed in the late 1980s (Hudak, Wadler, 1988) based on, at that point, a good ten years of experience designing and implementing similar languages, most notably a series of languages developed by David Turner in the late 1970s and early 1980s (Turner, 1976; 1985). Although research continues on the design of Haskell, the version used in this textbook, Haskell 98 (Augustsson, et al., 1999), is the latest and most stable version of the language and its libraries.

Haskell was named after the logician Haskell B. Curry who, along with Alonzo Church, established the theoretical foundations of functional programming back when computers themselves were only a gleam in researchers' eyes. A curious historical fact is that Haskell Curry's father, Samuel Silas Curry, helped to found and direct a school in Boston called the School of Expression. Because pure functional programming centers around the notion of an expression, I thought that The Haskell School of Expression would be a good title for this book.

A Brief Account of Language Success Stories

It's hard to predict just how it is that a language becomes popular. Fortran became popular because it was the first high-level language and a welcome alternative to assembly language, and ultimately because it was a good vehicle for coding numerical algorithms in the domain of scientific computing. C (Kernighan and Ritchie, 1978) was not revolutionary by any means, often being described as a high-level assembly language. But it found a niche in Unix and systems-level programming, and from there to other operating system platforms. Cobol (Cobol, 1968) was designed from day one for business applications, and so made its mark. Java's (Gosling, Joy and Steele, 1996) recent astonishing rise in popularity is rather perplexing on one hand, yet quite understandable on another. As a language, it is simple and elegant, but certainly not revolutionary. Yet it found a niche in its use on the world-wide-web, which at the time was (and still is) a phenomenon in its own right. Lisp and Scheme (Rees and Clinger, 1986) for AI, Ada (Ada,79) for real-time applications, VHDL and Verilog for digital hardware design, and the list goes on.

From this discussion it appears that for a language to become popular it needs an application - a niche - in which it excels, or in which it at least was the first to arrive. Curiously, for most language designers, this is the opposite of what is desired. Most language designers would like their languages to be truly general purpose, able to solve all of the world's problems with great succinctness, clarity, and efficiency. As a result, many excellent languages out there, some with very decent implementations, will probably forever remain in obscurity because they never found their niche.

Although the designers of Haskell exhibited no exception to this ambitious approach to language design, in retrospect I wonder if there might be a plausible niche for Haskell. These sorts of things are mostly out of my control, of course, but I thought it would be fun to use multimedia - graphics, sound, and animation - as an underlying theme, embodied concretely through many examples and exercises, in this text. Multimedia is an application area that is certainly current and important, and one in which Haskell's advantages are highly visible.

In addition, one of the nice things about multimedia programming is that all of the really interesting (and hard!) problems faced by computer scientists over the past 30 years are found in the "virtual worlds" that we create. Nondeterminism, concurrency, state, time, efficiency, decidability, and others are all issues that must be addressed. Although I don't cover all of these issues in this text, multimedia programming nevertheless provides a good vehicle through which one could teach general topics in computer science.

I also hope that this text demonstrates the ease with which one can embed a domain-specific language in Haskell. In a more general sense, this might actually be the most profitable niche for Haskell, as there have been a number of success stories in this area already.

In any case, I hope that you enjoy working through the various multimedia programs as much as I have enjoyed creating them. At the same time, I hope that this text might help Haskell to find its niche and thus avoid the fate of obscurity described earlier. Haskell really is a beautiful language.

Why I Wrote This Book, and How to Read It

At the time I began writing this book there were not many other books about programming specifically in Haskell. But that wasn't the main reason I decided to tackle this task. More importantly, there was a need for a book that described how to solve problems using a functional language such as Haskell. As with any major class of languages, there is a certain mind-set for contemplation, a certain viewpoint of the world, and a certain approach to problem solving that collectively work best. If you teach only Haskell language details to a C programmer, she is likely to write very ugly, incomprehensible functional programs. But if you teach her how to think differently, how to see problems in a different light, functional solutions will come easily, and elegant Haskell programs will result. That, in a nutshell, is my goal in this textbook. As Samuel Silas Curry once said:

All expression comes from within outward, from the center to the surface, from a hidden source to outward manifestation. The study of expression as a natural process brings you into contact with cause and makes you feel the source of reality.

I encourage the seasoned programmer having experience only with conventional imperative and/or object-oriented languages to read this text with an open mind. Many things will be different, and will likely feel awkward. There will be a tendency to rely on old habits when writing new programs, and to ignore my suggestions about how to approach things differently. If you can manage to resist these tendencies, I am confident that you will have an enjoyable learning experience. Many of those who succeed in this process find that many of the things that they learn about functional programming can be applied to imperative and object-oriented languages - after all, most of these other languages contain a significant functional subset - and that their imperative coding style changes for the better as a result.

I also ask the experienced programmer to be patient while in the earlier chapters I explain things like "syntax," "operator precedence," and others because my goal is that this text should be readable by someone having only modest prior programming experience. With patience the more advanced ideas will appear soon enough.

If you are a novice programmer, I suggest taking your time with the book; work through the exercises, and don't rush things. If, however, you don't fully grasp an idea, feel free to move on, but try to reread difficult material at a later time when you have seen more examples of the concepts in action. For the most part this is a "show by example" textbook, and you should try to execute as many of the programs in this text as you can, as well as every program that you write. Learn-by-doing is the corollary to show-by-example.

Finally, although the text begins quite gently, it moves at a fairly rapid pace, and covers many advanced ideas in functional programming, some of which are not covered in any other text that I am aware of. So there is much here even for those who are already familiar with the basics of functional programming.

Suggestions to Instructors

All of the material in this textbook can be covered in one semester as an advanced undergraduate course. For lower-level courses, including possible use in high school, some of the mathematics may cause problems, but for bright students I suspect most of the material can still be covered.

I strongly encourage sticking to the order of the chapters in the book, which introduces Haskell language features as they are demanded by the underlying application themes (generally the chapters alternate between "concepts" and "applications"). If you are an experienced functional programmer, you will see instances early in the book where a lambda expression here, or eta-conversion there, will simplify things, but I have chosen to delay such simplifications in most cases. Flooding the student with too many features early on can be overwhelming.

The only exception to following the given chapter order is that Chapters 20 to 22 provide a somewhat independent thread on computer music, and can be covered anytime after Chapter 11. The most difficult chapter is probably Chapter 15, and the most dispensible chapters are probably Chapters 17 and 22. Also, if you want to omit nonmultimedia applications you might consider skipping Chapter 6, although that chapter contains the first introduction to infinite lists. Finally, Chapters 23 and 24 are short "tours" of the PreludeList Module and Standard Type Classes, respectively, and could be assigned as auxiliary reading, or covered piecemeal as related topics are introduced.

The web page http://www.cs.yale.edu/homes/hudak/SOE contains a great deal of useful information related to the text, including libraries, source code for each chapter, PowerPoint slides, and errata. You can send email to me at paul.hudak@yale.edu with feedback, questions, corrections, etc.

Haskell Implementations

There are several good implementations of Haskell, all available free on the Internet through the Haskell home page at http://haskell.org. One that I especially recommend is the Hugs implementation, a very easy-to-use and easy-to-install Haskell interpreter. Hugs runs on a variety of platforms, including PC's (Windows 95/NT), various flavors of Unix (Linux, Solaris, HP), and Mac OS. The Glasgow Haskell Compiler (GHC) supports the same libraries as Hugs, and has the benefit of being a true compiler instead of an interpreter.

All of the code in the book is compliant with the Haskell '98 standard, and has been tested on the Hugs '98 implementation of Haskell. Unfortunately, the graphics and animation applications rely on a library that was originally developed only for Windows 95/NT. You should consult the SOE web page for the latest information regarding compatibility with other platforms.

Acknowledgments

I learned that writing a textbook is not an easy task, and could not have been accomplished without the help of many friends and colleagues. I would especially like to thank Mark Jones, with whom I started this project, and who first suggested the use of the name School of Expression. I'd also like to thank John Peterson and Joe Fasel for help in writing A Gentle Introduction to Haskell (Hudak and Fasel, 1992), from which some of this text was adapted; Alastair Reid for help with the Hugs implementation and graphics libraries; Conal Elliott for many helpful suggestions and inspirations, especially concerning graphics and animation; Erik Meijer for feedback from using a previous version of this text in his class; Mark Tullsen for careful proofreading and tedious index generation; Tom Makucevich and John Garvin for help with computer music; Tim Sheard for feedback from using my book in teaching a functional programming course at Yale, and for creating great PowerPoint slides in the process; Zhanyong Wan for excellent feedback on the text as a Teaching Assistant in Tim's course; Sigbjorn Finne for writing the kaleidoscope program; Valery Trifonov for adapting the kaleidoscope program and other useful feedback; Linda Joyce for help with the indexing and excellent administrative support; Martin Sulzmann for help debugging graphics; Lauren Cowles, my editor, whose patience is extraordinary; and the many students in various classes at Yale who endured earlier versions of the text.

I would also like to thank the several United States funding agencies, most notably NSF and DARPA, who have provided considerable financial support for functional programming research at Yale and elsewhere.

Most of all, this work could not have been accomplished without the love and support of my family. Thank you Cathy, Cristina, and Jennifer.


Happy Haskell Hacking!

Paul Hudak
New Haven
June 1999

Contents   Next