Thomas VanDrunen
discrete mathematics ano
functional programmingDISCRETE MATHEMATICS AND
FUNCTIONAL PROGRAMMING
Thomas VanDrunen
Franklin, Beedle & Associates Inc— Dedication —
To Esther.
Instead of the brier shall come up the myrtle.
Isaiah 55:13
President and Publisher _Jim Leisy (
[email protected])
Production ‘Tom Sumner
Associate Jaron Ayres
Printed in the U.S.A.
Names of all products herein are used for identification purposes only and are trademarks
and/or registered trademarks of their respective owners. Franklin, Beedle & Associates,
Inc., makes no claim of ownership or corporate association with the products or com-
panies that own them.
(©2013 Franklin, Beedle & Associates Incorporated. No part of this book may be repro-
duced, stored in a retrieval system, transmitted, or transcribed, in any form or by any
‘means—electronic, mechanical, telepathic, photocopying, recording, or otherwise—
‘without prior written permission of the publisher. Requests for permission should be
addressed as follows:
Rights and Permissions
Franklin, Beedle & Associates Incorporated
22462 SW Washington St.
Sherwood, Oregon 97140
Library of Congress Cataloging-in-Publication data:
‘VanDrunen, Thomas.
Diserete mathematies and functional programming / Thomas VanDrunean.
ages cm
Includes index.
ISBN 978-1-59028-260-1 (alk. paper)
1, Computer science-Mathematics. 2. Functional programming (Computer science)
1 Title.
(QA76.9.M35V385 2013
005.1'14-de23
2012034560Preface
Introdue
Contents
(tothe instructor),
tion (to the student).
Acknowledgments.
PART
Chap
1
2
b
‘4
13
16
"7
i
13
110
iit
ip
Lb
Tie
Ls
1 FOUNDATIONS
ter 1 Set
‘Your mathematical biography.
Reasoning about items collectively
Set notation
Set operations
‘Verifying facts about sets
Values, expressions, and types in ML.
Characters and strings
Cardinalit, dsjointness, and partitions
Cartesian products
Making your own types
Making your own operations
Recursive functions
Statements and exceptions.
Extended example: A cumulative song,
Special topic: Comparison with object-oriented programming
Chapter 2 List
2a
22
23
24
Lists.
Functions on lists
Datatypes that use lists
Powersets
63
aaseContents,
2.5 Case expressions and option types 2
2.6 Extended eampl: A language procasor a4
2.7 Special tpi: sts ve. tuples ve rays 2
Chapter 3. Proposition 95
BA Forms or
32. Symbols 98
3.3 Boolean values ‘00
34 Logical equivalence. : “02
35 Conditional propostions 106
3.6 Conditionals and natural language 109
3.7 Conditional exreasions a2
38 Arguments 116
3.9 Using argument forme for deduction 320
310 Predicates 123
311 Quantiation 124
GHD Mutite qusiiaton : “30
313 Quantifstion and algorithms Be
3:14 Quantification and arguments 136
315. Edended example: Verifing arguments automaticaly 140
316 Special topic: Quantification and natural language 18
Chapter 4 Proof
“41 General outine
42° Subset proofs
43 Seteqalty
44 Set emptiness
4.5. Conditional proo
4.6 Integers
4.7 Biconditionals.
4.8 Warnings
4.9 Case study: Powersets
410 From theorems to algorithm:
411 Extended example: Solving games.
4.12 Special topic: Russell's paradox.
PART II core
Chapter 5 Relation
S11 Definition
5.2 Representation.
5.3 Image, inverse, and composition
5.4 Properties of relations.
5.5 Equivalence relations
5.6 Computing transitivity
5.7 Transitive elosure
5.8 Partial ordersContents
5.9 Comparability and topological sort.
5.10 Extended example: Unification and resolution.
5.11 Special topic: Representing relations
Chapter 6 Self Reference
‘6.1 Peano numbers
62 Trees.
6.3 Mutual recursion
6.4 Structural induction,
65 Mathematical induction
6.6 Mathematical induction on st
6.7 Program correctness.
68 Sorting
6.9 eration
6.10 Loop invariants.
6.11 From theorems to algorithms, revisited
6.12 Extended example: Huffman encoding...
6.13 Special topic: Recursion vs. iteration
Chapter 7 Function
74 Definition
72. Function quay.
7.3 Functions as first-class values
7A Images and inverse images.
75 Map
7.6. Function properties.
77 Inverse functions
7.8 Function composition
79° Cardinalty
710 Counting
71 Permutations and combinations.
712 Currying
7.13 Fixed-point iteration .
7.14 Extended example: Modeling mathematical functions.
7.15 Special topic: Countatility
PART Ill ELECTIVES
Chapter 8 Graph
8.1 Definition and terms.
8.2 Propositions on graphs
83. String about a graph
8.4 Isomorphisms.
8.5 A garden of graphs.
8.6 Representing graphs.
8.7 Extended example: Graph algorithms
8.8 Special topic: Graph coloringChap
on
92
93
oa
95
96
a7
98
99
910
oat
Chap
01
102
103
to
1s
os
107
Contents,
ter 9 Complexity Class
Recurrence rations.
Compecty of algorithms
‘Analyzing sorting algoriths
‘Atematie examples of analyzing algorithms.
Bigoh complexity cases.
Big theta and family
Properties of complesty cases
Tables
Memoiation
Extended example The Knapsack Problem
Special topic: P vs NP
ter 10 Lattice
Definition and terms
Propositions on latices,
Isomorphisms,
Modular and distributive lattices
Implementing lattice operations
Boolean algebras.
Special topic:
al logic circuits
Chapter 11 Group
na
n2
13
4
5
16
Preliminary terms
Definition
|somorphisms,
Subgroups:
‘Agarden of groups.
[Extended example: RSA encryption
Chapter 12 Automaton
RA
22
123
4
5
126
R7
28
19
12.10
Alphabets and languages.
Deterministic finite automata
Nondeterminism
Regular expressions.
Language model equ
Context free grammars.
Push-down automata,
“The lambda calculus.
Hierarchies of computational models.
Special topic: Computability,
lence and limitations
Anpendic A Patterns for proofsPreface (to the instructor)
This text's approach
This text provides a distinct way of teaching discrete mathematics. Since discrete
mathematics is crucial for rigorous study in computer science, many texts include
applications of mathematical topics to computer science or have selected topics
of particular interest to computer science. This text fully integrates discrete math-
ematics with programming and other foundational ideas in computer science.
In fact, this text serves not only the purpose of teaching discrete math. It is
also an introduction to programming, although a non-traditional one, Functional
programming is a paradigm in which the primary language construct is the func-
tion—and function here is essentially the same as what it is in mathematics. In
the functional paradigm we conceive the program as a collection of composed
functions, as opposed to a sequence of instructions (in the imperative paradigm)
or a set of interacting objects (in the object-oriented paradigm). Dominant com-
puter science curricula emphasize object-oriented and imperative programming,
‘but competence in all paradigms is important for serious programmers—and
functional programming in particular may be appropriate for many casual pro-
grammers, too. For our purposes, the concepts underlying functional program-
ming are especially grounded in those of discrete mathematics.
Discrete mathematics and functional programming are equal partners in this,
endeavor, with the programming topics giving concrete applications and illustra-
tions of the mathematical topics, and the mathematics providing the scaffolding
for explaining the programming concepts. The two work together in mutualPreface (to the instructor)
illumination. (The time spent on the math and programming content streams,
however, is closer to a 60/40 split.)
Discrete math courses and texts come in many flavors. This one emphasizes
sets, using the set concept as the building block for discussions on propositional
logic, relations, recursion, functions, graphs, complexity classes, lattices, groups,
and automata. Of course the specific topics themselves are subservient to our
real object: teaching how to write proofs.
‘The presentation of functional programming is based on the classic approach
embodied in Abelson and Sussman’s Structure and Interpretation of Computer
Programs (SICP) [1]. In short, it is SICP-ight, modernized and adapted to the
discrete math context, and translated into the ML programming language.
Rationale
Why teach discrete mathematics—or functional programming—this way? This
approach is proposed as a solution to a variety of curricular problems.
Serving the constituencies. As a rookie professor, the author taught a dis-
crete math course designed for math majors but filled with math-averse computer
science majors fulfilling their math requirement and, in the same semester, an
introductory programming course designed for computer science majors but filled
with math majors fulfilling their computing requirement. Needless to say, much
effort went into convincing each population that the course was relevant to them.
If the supporting courses really are so important, than why do these need to
be separate tasks? Why not offer a single course intertwining programming and
proof-based discrete mathematics, making their mutual relevancy explicit? The
math content will motivate the math majors and make the programming more
familiar and palatable. The programming content will sweeten the math pill for
the computer science majors.
Moreover, bringing the two populations together will allow them to learn
from and help each other. This text's premise is,
Math majors should learn to write programs
and
computer science majors should learn to write proofs
together.Preface (to the instructor)
Further still, this text is appropriate for non-majors who are interested in a
compact experience in both fields. Accordingly, liberal arts colleges will find this
approach particularly useful for interdisciplinary cross-pollination.
Theory vs practice. Where do the foundations of computing belong in un-
dergraduate curriculum? Some departments have faced battles between, on one
hand, those wanting to use the foundations and theory of computer science as
a gateway for incoming majors and, on the other, those who want to ensure
students develop programming skills immediately.
With this text, you do not have to choose. While this is not explicitly a course
on the theory of computation or other foundations of computer science, discrete
mathematics provides the right context for previewing and introducing these
ideas. Moreover, the programming content keeps the theory grounded in practice.
Coverage of functional programming. Despite the paradigm’s importance,
finding the right place for functional programming in an undergraduate cur-
riculum has been tricky. From the 1980s through the early 2000s, several good
texts were produced for a functional-first approach to teaching programming,
but the approach never became dominant. Most students receive a brief expo-
sure to functional programming in a sophomore-level programming languages
course, if at all. As the undergraduate curriculum becomes crowded with new
topics vying for attention and old, elective topic being pushed earlier (mobile
computing and concurrency, for two examples), the programming languages
course absorbs much of the pressure. The temptation to jettison functional pro-
gramming altogether is strong.
This would be a great mistake, Many design patterns in object-oriented
programming are imports of ideas from functional programming, Features from
functional languages are appearing in languages not traditionally thought of as,
functional (Python, C#, and Java 8). And functional programming is a handy
‘way to reason about questions in the foundations of computer science
‘The solution proposed here is to put functional programming in the discrete
math course. This way functional programming is seen early (ideally freshman
or sophomore year) and, for computer science majors, is taught in parallel with
a traditional introduction to programming course covering imperative, object-
oriented, and concurrent programming.
Why ML? The ML. programming language—to be specific, Standard ML. or
‘SML—is chosen as the language for this book, but the approach is not inherentlyPreface (to the instructor)
tied to ML. In choosing a language, our first goal should be to do no harm—the
language, especially its syntax, should not get in the way. ML was chosen for its,
simplicity, particularly its similarity to mathematical notation. Students used to
‘mathematics should find the syntax natural. For students with prior programming
experience, it is not much of a transition syntactically from, say, Java, either.
With a lite effort, this text could be used with programming examples and
exercises in F#, OCaml, or Haskell. With a little more effort, a Lisp dialect or
even Python could be used.
Themes
A diverse set of topics fall under the discrete mathematics umbrella, but certain
themes come up throughout the book.
Proof and program. This text strives to make skill in proof-writing and pro-
gramming transferable from one to the other. The interplay between the two
content streams shows how the same thinking pattems for writing a rigorous
proof should be employed to write a correct and usefull program.
Thinking recursively. Many students have found recursion to be one of the
most mind-boggling parts of learning programming. The functional paradigm
and the discrete math context make recursion much more natural. Recursive
thinking in both algorithms and data structures is a stepping stone to proofs
using structural induction and mathematical induction,
Formal definitions. Precision in proofs hangs on precision in the definitions
of things the proof is about. Informal definitions are useful for building intuition,
but this text also calls students’ attention to the careful definitions of the terms.
Analysis and synthesis. Analysis is taking something apart. Synthesis is
putting things together. Whether we ate proving a proposition or writing a
program, thinking through the problem often comes into two phases: break-
ing it down into its components and assembling them into a result. In a proof
this manifests itself in a first section of the proof where the given information,
is dissected using formal definitions and a second section where the known
information is assembled into the proposition being proven, again using formal,
definitions. (We call that the analytical and synthetic use of the definitions.) APreface (to the instructor)
similar pattern is seen in operations on lists—analytical operations that take lists
apart and synthetic operations that construct them.
How to use this text
Audience. Ideally this text can be used by first-year undergraduates who are
well-prepared mathematically—that is, able to reason abstractly and willing to
think in new ways. Weaker students mathematically may be better served by tak-
ing such a course in their sophomore or junior years. The only hard prerequisites
are high school algebra and pre-calculus. Occasionally the text uses examples
from differential or integral calculus, but these can be skipped without harming,
the general flow the material.
The structure of each chapter. The names of the chapters are singular
nouns: Set, Proof, Function, Graph, etc. This is to draw attention to each chapter's
primary object of study. The opening sections of a chapter provide foundational
definitions and examples, followed by the most important properties, proposi-
tions (and proofs) about the object of study, and finally applications of them,
especially computational applications.
All sections except special topics or those providing a very general introduc-
tion end with a selection of exercises. Almost all chapters end with an extended
programming example (including a project) and a special topic that condenses,
an advanced mathematical or computational idea to an accessible level based.
on the contents of the chapter.
The structure of the book. The chapters are collected into three parts. Set,
List, Proposition, and Proof constitute the Foundations—ideas and skills for a
student to master before seeing the other material which is built on them. The
Core part of the text is the chapters on Relation, Self Reference, and Function.
‘The Foundations and Gore chapters build on each other in sequence.
‘The Elective chapters—Graph, Complexity Class, Lattice, Group, and Au-
tomaton—represent more advanced topics, building on both the foundations
and the core. These chapters are almost completely independent of each other.
‘The instructor may pick and choose from these and even reorder them with very
little difficulty. A new recurring theme emerges in Graph, Lattice, and Group,
that of isomorphism, structural equivalence between mathematical objects.Preface (to the instructor)
Pacing and planning. There is a wide range of difficulty in this material,
and accordingly it can be adapted to courses at several levels. The Electives part
naturally contains more advanced material, but particularly challenging sections,
op up at various points in the book. These include Sections 4.9, 5.9, 6.7-6.10,
7.9, and 10.4. These (and any of the extended examples or special topics) can
be omitted without harming the flow of the text.
For average to strong students in their freshman or sophomore year, most of
Chapters 1-7 can be covered in one semester—the instructor is encouraged to
choose some of the challenging or extended example sections to cover, but not
all, The chapters in the Elective part can be used ina second semester, although
there may be time at the end of a first semester to cover select topics from the
Elective part.
‘The author has used this material for six years in a one-semester course with
this approximate outline (mapping class days to sections, assuming a four-hour
course meeting three days a week):
Day 1: 1.1-1.3 Day 15: 4.1-4.2 Day 27: 6.1-6.2
Day 2: 1.4-1.6 Day 16: 4.3-4.4 Day 28: 6.4
Day 3: 1.7-1.9 Day 17: 45-48 Day 29: 6.5-6.6
Day 4: 1.10-1.13 Day 30: 6.9-6.10
Day 5: 2.1-2.2 Day 19: 4.10-4.11 Day 31: 6.10-6.11
Day 6: 2.3-2.4 Day 20: 5.1-5.3 Day 32: 6.12
Day 7: 2.5-2.6 Day 21: 5.4 Day 33: 7.1-7.3
Day 8: 3.1-3.4 Day 22: 5.5 Day 34: 7.4-7.5
Day 9: 3.5-3.7 Day 23: 5.6-5.7 Day 35: 7.6-7.8
Day 10:3.8-3.9 Day 24: 5.8-5.9 Day 36: 7.9
Day 11: 3.10-3.13 Day 25: Review; 4. Day 37: Review; 7.15
Day 12: 3.14 Day 26: Test Day 38: Test
Day 13: Review
Day 14: Test
This schedule leaves about two weeks at the end of the semester for topics
chosen from later chapters.
For a class of students who are less mathematically prepared, this text can
be used in a more slowly paced course that covers Chapters 1-3 and roughly the
first half of each of Chapters 4-7.
For a class of very experienced students, this text can be adapted to an
advanced course where Chapters 1-4 are treated very quickly; leaving time for
significant coverage of material from Chapters 8-12.Preface (to the instructor)
Any students unfamiliar with the citation system should note that numbers in
square brackets refer to bibliography entries. Supplemental materials and other
related resources can be found at http://es.wheaton.edu/~tvandrun/
mfp.Introduction (to the student)
So you have a book entitled Discrete Mathematics and Functional Programming on
your shelf. That has to be a hard subject to explain to your roommates. Have they
‘made any snide remarks about indiscreet math or dysfunctional programming?
First, what these words mean. Most of the mathematics taught in high school
and college curricula revolve around preparing students for calculus, teaching
them calculus, showing them applications of calculus, and teaching them to
prove things, mostly about calculus. The backbone of all this is the real number
line, which you have learned can be broken down into smaller and smaller seg-
‘ments, all of which are still filled with real numbers. There are no gaps between,
real numbers, no matter how close together, which are not filled with an infinite
number of real numbers. Thus the mathematics of real-number land is continu-
ous mathematics.
We love calculus, but there are other important branches of mathematics
that get short changed, things like set theory; symbolic logic, number theory (the
study of natural numbers and integers), graph theory, the study of algorithms
with their analysis and correctness, matrices, sequences and recurrence relations,
counting and combinatorics, probability, and languages and automata. Any of
these could become a course of their own, but to make a survey of them accessible
to all students, college math curricula have made courses out of a sampling of
these topics and called the courses discrete mathematics. That term has two main
explanations: These topics always have discrete—that is, separable, indivisible,
or quantized—objects in view; and these topics stand in contrast to continuous
mathematics. You might say the difference between discrete and continuous isIntroduction (to the student)
like that between digital and analog.
Next time you are in the kitchen, look around for the discrete/continuous
distinction. Some ingredients can be measured in amounts of any size: flour
and milk are continuous. But eggs are discrete—they must be used in whole
egg units. What kind of stove do you have? An electric stove can have discrete
settings (in my house growing up, ours was push-button), but the bumer knobs
on a gas stove are continuous. You can even see it in how you serve dessert. In
some families the server asks everyone how big a slice they want; in others the
pie is sliced in equal portions and you take it or leave it. Do you consider pie
slices to be continuous or discrete?
About the other half of the title: Computer science education almost always
begins with programming. Two of the major brands (“paradigms”) of program-
ming are imperative programming, where a computer program is series of com-
mands, and object-oriented programming, where a program is a collection of
interacting objects. A typical introductory programming course will be a mixture
of the two. But there is an alternative. In the functional paradigm, a program is
built from a collection of functions, each of which is a little program in its own
;ht. We will not venture into a debate on the relative merits of these paradigms.
It is safer just to say that a serious programmer needs to be competent in all of
them.
‘This text, Discrete Mathematics and Functional Programming, is an effort to
bring together the material from discrete mathematics most useful to computer
science and the programming material most accessible through mathematics.
Learning these two content streams does not have to be separate tasks, but rather
the insights and thought patterns you gain through writing mathematical proofs
can transfer into those you need to write computer programs and vice versa.
Uniting these two also illuminates the ideas that fall at their intersection.
The goal of this book is to train your mind. Itis to teach you to reason at the
level of precision necessary to write rigorous proofs and correct programs. Itis to
teach you to think recursively, that is, to reason about things with self-referential
definitions. It is to teach you to think formally about abstract structure. It is
to teach you to organize your thoughts when writing a proof or program into
analysis (taking things apart) and synthesis (putting things together).
As you embark on this journey, make every effort not to be intimidated. The
material contained here spans a wide range of difficulty. If some of what you see
when flipping through seems well beyond your reach, do not think that for that
reason you won't be able to get the foundational material. Some of the harderwi Introduction (to the student)
parts, especially in Chapters 8-12 are “elective” and aren't crucial for learning
the main points of this study. On the other hand, if you learn the basics well and
persist with hard work, you will be able to tame even the advanced parts.
On that note, a special word to self-directed students, reading this book out-
side of a course for which itis a required text (this goes also for students who,
having taken a course covering the first half of the book, are working through the
second half on their own). The chapters in the “Elective” part are dense. Their
topics—graph theory, computational complexity, lattices and related structures,
group theory, and theory of computation—each deserve a course in themselves.
‘The presentation here is to get you acquainted with what these fields hold and
help you decide if you want to pursue them further. I have not confined the
presentation in those chapters only to the fields’ most introductory material. In
each chapter you will find some serious results of that field made accessible to
readers with no more background than is covered by this book. They will take
serious work to digest but will repay study.Acknowledgments
‘The people who most deserve my gratitude in this project are my family—my wife
Esther, our daughter Annika, and our son Isaac. Their support, encouragement,
patience, and love made this work possible. The writing of this book is closely
tied to our family’s milestones. I churned out the first cut of the manuscript
(for use in my own classes) during the summer Esther and I became engaged.
“The first major rewriting was done the summer when Annika was an infant—I
particularly remember pecking out a few paragraphs at Annika’s nap times dur-
ing my three weeks as a stay-at-home dad. I worked on finishing the text and
preparing it for publication during Isaac’s “first two summers” (one summer on
the inside, the other on the outside). Thanks, too, for the encouragement of my
and Esther’s extended families—especially for not ribbing me too much about
how long it was taking,
Thanks to Jim Leisy and Tom Sumner at Franklin, Beedle who patiently
shepherded a first-time author through the process of publishing a book. Thanks
also to the reviewers for their valuable suggestions, not only improving the pres-
entation but also catching technical errors, Any remaining mistakes are mine.
‘Two of my teachers played an indirect but important role in this work. The
exploration of number sets in Section 1.1 is based on the presentation my high
school math instructor, Dick Zylstra, would make on the first day of class each year.
also credit him for helping me find math interesting for the first time. During
graduate school Jens Palsberg (then of Purdue, now of UCLA) taught me the role
of proofs in computer science. Later as a rookie professor I had a conversation
with him about prioritizing my time among various potential projects. He sensedAcknowledgments
‘my interest in writing this book and encouraged me to do it. His approval gave
me confidence that I was not running my race in vai
‘Thanks to all my department colleagues at Wheaton College (IL) for their
encouragement and support. In particular Robert Brabenec, Cary Gray, Don
Josephson, Steve Lovett, Terry Perciante, and Mary Vanderschoot each gave
useful suggestions at various points along the way.
Much thanks is owed to the many students on whom this material was
classroom-tested over the course of six years. Their feedback has been crucial to
its improvement. The following either served as teaching assistants, read drafts,
were grand champion mistake-finders, or proposed an important example or
exercise: Jeremy Woods, Ben Ashworth, Chet Mancini, John Charles Bauschatz,
Daniel Turkington, Andrew Wolfe, Sarah Cobb, Neile Havens, Kendall Park,
Drew Hannay, Jacqui Carrington Goertz, Tim MacDonald, Ben Torell, and Amy
Nussbaum,
‘The automata in Chapter 12 were rendered using the VAUCANSON-G package
by Sylvain Lombardy and Jacques Sakarovitch.
Talso greatly appreciate the following reviewers; they provided expert help
and offered many suggestions for improvemer
Chuck Allison, Utah Valley State University
Robert Easton, California Polytechnic State University, San Luis Obispo
Lester McCann, University of Arizona
Brian Palmer, Depauw University
Mare Pomplun, University of Massachusetts, Boston
Michael Stiber, University of Washington
My T. Thai, University of Florida
Finally, thanks be to God for his grace and mercy. Soli Deo Gloria. Avi tov
oltctipudy To8 HeoD . . . Tv hoyuelly Actpeicey Gpdv. “In light of the mercies of
God. . . your rational service.” Rom 12:1.
Poon [A] A torentPart I
FoundationsChapter 1 Set
(Our staring point in our exploration of discrete mathematics is the set. This is
not the only place where we could begin—some courses, for example, put for
‘mal logic first, since itis the most fundamental, simple system. Logic, however,
is about sentences. We start with sets because it allows you to start by learn:
ing nouns. Sets also make for a familiar stepping-off point from continuous
mathematics to discrete mathematics,
‘This chapter and the next form an important unit. In this chapter, in addi
tion to set concepts you also will learn the basics of the ML programming lan
‘guage, and by the end of it you will be able to write simple programs yourself.
‘The most important groundwork for ML, though, begins in the next chapter
‘Some of the mote complicated set concepts are reserved until then as well
Chapter goals. The student should be able to
‘+ describe sets and relationships among them, both informally and using
‘mathematical notation
+ evaluate operations on sets.
+ perform simple arithmetic operations in Ml.
+ verify propositions about sets using Vena diagrams.
+ compose types in ML using the datatype construct.
+ compose simple functions in ML.LL YOUR MATHEMATICAL BIOGRAPHY
[1.1] Your mathematical biography
You may be wondering what discrete mathematics is, To get there, we will
retrace all the math you have learned until now. That might sound like a tall
order for a first section, but we can expedite the process by highlighting some
major events—say, every time you learned about a new kind of number
‘Try to put yourself back to when you first realized what a number was. At
some point you began to conceptualize differences in quantities (10 Cheerios is
‘more than 3 Cheerios), and eventually you learned to count: 1, 2, 3, ...up to
the highest number you knew. We call these numbers the natural numbers, and natural murbers
‘we will represent ali of them with the symbol
We are using this to symbolize all of them, not each of them, and that is an
important distinction. IN is not a variable that can stand for any natural number.
It is a constant that stands for all natural numbers as a collection,
As time went on, you learned more natural numbers—for example, learning
that 100 comes after 99. Since there are an infinite number of natural numbers,
you can line up the natural numbers starting at one (which is essentially what
you are doing when you count) and keep going forever and still stay within the
realm of natural numbers. But it is not as natural to go the other direction.
What comes before one? At some point early in grade school, you came to
accept ero as a number, just a different kind of number. We will designate
all natural numbers together with 0 to be whole numbers, and represent them whole numbers
collectively by W.
0 is a whole number but not a natural number. 5 is both. In fact, anything
that is a natural number is also a whole number, but only some things (specif-
ically, everything but zero) that are whole numbers are also natural numbers.
‘Thus W is a broader category than N.
‘Tangent: What is the ability to count?
In this story, | have suggested that leaming the names of new numbers constitutes expanding
mathematical knowledge. Many two-year-olds, however, can recite numbers in order, even appearing
to count objects, without understanding what the words mean.
Following an experiment described by Barbara Samecka and Susan Carey, [poured a pile of
buttons in font of my two-year-old daughter, who can recite numbers up to ten very wel. When 1
asked for one button, she placed one button in my palm. Similarly she was able to give me two
‘buttons when asked, When I asked for three buttons, however, she again gave me two, When I told
her that she had given me two although Lasked for three, she took away the two she had given me
and in place of them gave me two others, “Three” didnot have a meaning to her different from “two.”
Samecka and Carey distinguish “one”-knowers, "wo" knowers, “three"-knowers, and even
“four"-knowers among, toddlers, before the children ean generalize the concept of named quantities,
‘The transitions between understanding individual numbers may be months apart [29]CHAPTER 1. SET
integers
rational numbers
Of course in math class you did not merely meet new numbers. You also
learned things we can do with numbers, like addition and subtraction,
Any time you added two whole numbers together, you got another whole
number as a result. Subtraction, however, forced you to face a dilemma: what
happens if you subtract a larger number from a smaller number?
‘The problem is, W is insufficient to answer this question. No whole number
is the difference between 3 and 20; in technical terms, ¥ is not closed under
subtraction. ‘To fix this problem, we invented negative numbers. We call all
whole numbers together with their opposites (that is, their negative councer-
parts) integers, and we use Z (from Zahlen, the German word for “numbers”) to
symbolize the integers. Now we could do addition and subtraction on integers
and stay within the realm of 2. Multiplication worked fine, too,
Division was a different story. What happens if we divide 5 by 2? (In the
history of mathematical thinking, we can imagine two cavemen arguing over
how to split five apples. Physically, they could chop one of the apples into
two equal parts and each get one part, but how can you describe the resulting
‘quantity that each caveman would get?)
‘Human languages handle this with words like “half.” Mathematics handles
this with fractions, like # or the equivalent 24, which is shorthand for 2++ 4. We
call numbers that can be written as fractions (that is, ratios of integers) rational
numbers, symbolized by @ (for quotient). Since a number like 5 can be written
as 3, all integers are rational numbers.LL YOUR MATHEMATICAL BIOGRAPHY
Just as whole numbers could not handle subtraction and integers could not
handle division, in a similar fashion geometry exposed the insufficiency of ra-
tional numbers. For example, an isosceles right triangle with sides of length 1
inch has a hypotenuse of length v/2 by the Pythagorean theorem. A circle with
diameter 1 inch has a circumference of
eC
V2 and 1 cannot be written as fractions, and hence they are not rational
‘numbers. However, these illustrations on paper prove that 2 and = are mea-
surable quantities. We call all of these "possible real world quantities” real
numbers, and symbolize them by R. real numbers
Here is a category you might not remember learning: real numbers can
be split up into two camps—algebraic numbers (A), each of which is @ root to she numbers
some polynomial function with integer coefficients (\/T and all the rationals are
algebraic); and transcendental numbers (‘), which are not. transcendental mutbersCHAPTER 1. SET
‘To play this game a little more, let us go back to talking about negative
numbers. We first considered negative numbers when we invented the inte-
gers. However, as we expanded to rationals and reals, we introduced both new
negative numbers and new positive numbers. ‘Thus negative (real) numbers
considered as a collection (3) cut across all ofthese other collections, except
‘Wand N.
“To finish off the picture, remember how N, Z, and Q each in turn proved to
bbe inadequate because of operations we wished to perform on them. Likewise
is inadequate for operations like square root. What is YI? Not a real number,
complex numbers at any rate. To handle that, we have complex numbers, ©.1.2. REASONING ABOUT ITEMS COLLECTIVELY
1.2] Reasoning about items collectively
‘These circle diagrams and symbols representing various collections of numbers,
like all concepts and their representations, are tools for communicating ideas
and reasoning about them. ‘The following table lists various sentences that
‘express ideas using the terminology introduced in the preceding exercise. In
the right column we write these statements symbolically. We will introduce the
symbols formally later.
5 is a natural number (or the collection of natural numbers 5eN
contains 5).
All integers are rational numbers. ZCQ
Merging the algebraic numbers and the transcendental num- R=AUT
bers makes the real numbers.
Negative integers are both negative and integers,
‘Transcendental numbers are those real numbers that are not T=R-A
algebraic numbers.
[Nothing is both transcendental and algebraic, or the collection Tha=0
of things both transcendental and algebraic is empry.
Adding 0 to the collection of natural numbers makes the col- w
lection of whole numbers.
Since all rational numbers are algebraic numbers and all al-
gebraic numbers are real numbers, it follows that all rational
numbers are real numbers.
ere
ninin
BR >
‘Notation Note: A slight break from convention
‘The symbols Z, Q, R, and C are conventionally used just as we use them inthis book, for integers,
rationals, reals, and complex numbers. Similarly, the way that we denote the positive or negative
numbers in a set (R or Q>, as examples) is standard
‘The terms whole number and natural number are not used as consistently, however Some authors
use them interchangeably or reverse the definition we are using. The symbol ‘usually stands forthe sec
(0, 1,2,3,...) and * stands for the same set except with 0 removed. This book strictly uses natural
numbers for {1,2,3,, ..} and whole numbers for (0,1, 2,3, ...), We use SY and % to be consistent
‘with this, even though it differs from convention.
The symbols. and Tare noc standard. ( does have a special meaning inthe field ofring theoryCHAPTER 1. SET
element
rimiive corms
Inall these sentences, we are dealing with two different kinds of nouns: on
one hand we have 5, 3, V/2, x, 21+ 3, and the like; on the other hand we have
things like N, Z,Q,1B, ‘and C. "We have been referring to the former by terms
such as “number” or “item,” but the standard mathematical term is element. We
have called any of the latter category a “collection,” but the mathematical term
is set. Informally, a set is a collection of items categorized together because of
perceived common properties.
This is the first shift in your thinking from continuous mathematics (such
as pre-calculus and calculus) to discrete mathematics. Up till now, you have
concerned yourself with the contents of these sets. In discrete mathematics, we
will be reasoning about sets themselves.
‘There is nothing so special about the sets we mentioned earlier. We can de-
lare sets arbitrarily—such as the set of even whole numbers, or simply the set
containing only 1, 15, and 23. We can have sets of things other than numbers:
asset of geometric points, a set of matrices, or a set of functions. But we are not
limited to mathematical objects, either. Grammatically, anything that is a noun
can be discussed in terms of sets.
Since set is a noun, we can even have a set of sets—for example, the set of
number sets completely enclosed in B, such as @,2, ¥W, and N.
Nevertheless, sets themselves are abstract ideas, According to Hrbacek and
Jech,
Sets are not objects of the real world, like tables or stars; they are
created by our mind, not by our hands. A heap of potatoes is not a
set of potatoes, the set of all molecules in a drop of water is not the
same object as that drop of water[17].
It is legitimate, though, to speak of the set of molecules in the drop and of
the set of potatoes in the heap.
This course emphasizes precise definitions. Not only does mathematical
rigor rely on them, bur in all areas of study, correct use of vocabulary reflects
full understanding of the concepts. However, one thing we will not define for
‘you are the terms set and element, and that is because they are primitive terms.
Primitive terms are the simplest building blocks we use in defining other things
and are therefore undefinable themselves.
‘Think back to high school geometry. You met terms like point, line, and
plane through their analogy in the physical word: a point is like a dot (a small
‘mark such as made on paper) but infinitely small, a line is like a taut string
but extending forever, and a plain is like a flat surface as on a table but, again,
infinite. These are not definitions, though.
Instead, geometry is founded on a set of axioms (also called postulates) that
describe the relationships among points, lines, and planes—for example, that
exactly one line exists connecting two distinct points. They are the starting
assumptions from which geometry is constructed.
Ser theory is likewise grounded in a series of axioms. Here are two, to give
a flavor of what these look like.
101.3. SET NOTATION
Axiom 1 (Existence.) There is @ set with no elements,
Axiom 2 (Extensionality.) If every element of a set X is an element of a set ¥
and every element of ¥ is an element of X, then X= Y.
How do we know there is such a thing as an empty set? Because we say so. emp set
Itis justa rule of the game,
‘The second axiom captures what we mean for two sets to be equal, Notice
that this means that sets are unordered, or that the order in which we present
the elements of a set is unimportant. We also can combine these two axioms to
obtain a new result, that there exists only one empty set, because if we had two
sets each with no elements, Axiom 2 implies they are in fact the same set.
‘A complete axiomatic formulation of set theory is intricate and beyond our
scope, We will introduce primitive concepts as we go along as needed. The
important point is that we start with presupposed propositions about undefined
terms and derive other facts from these.
[1.3] Set notation
We can describe a set explicitly by listing the elements of the set inside curly
braces. Order does not matter in a set, so, for example, the set of primary colors
is
{Red, Green, Blue} = {Green, Blue, Red} = {Blue, Red, Green} = {Blue, Green, Red}
When we use the phrase set notation, we mean this explicit listing of elements
in curly braces.
It is possible for a set to contain only one item, for example (Red}, but we
still distinguish that set from the item itself, that is Red (Red). Moreover
{) stands for a set with no elements, that is, the empty set, but we also have a
special symbol for that, 6.
The symbol € stands for set membership and should be read “an element
of” or *is an element of", depending on the grammatical context (sometimes
just “in” works if you are reading quickly).
Tangent: The nature of definition
‘What makes a good definition? Consider a typeal definition feom a dictionary
definition + a statement expressing the essential nature of something. [20]
‘To define a noun, the dictonary-vriters began with a more general noun (statement) and then
narrowed it (expressing the essential nature...) In other words, to define a noun, we need to put a
boundary around the set of things we can label with that noun (etymological, o define means to set
limits around). Compare this with N = (x € Z | x > 0}: Z is the more general set, x > 0 isthe qualifier
uCHAPTER 1. SET
Red ¢ (Green, Red}
‘The curly braces can be used more flexibly if you want to specify the ele-
‘ments of a set by property rather than listing them explicitly, Begin an expres-
sion like this by giving a variable to stand for an arbitrary element of the set
being defined, a vertical bar (read as “such that”), a statement that the element
is already a member in another set, and finally a statement that some other
property is true for these elements. For example, one way to define the set of
natural numbers is
N={reZ|z>
0)
‘which reads “the set of natural numbers is the set of all r such that « is an inte-
xger and « is greater than 0.” But there are many ways to describe or name sets.
Recall from pre-calculus that you can specify a range on the real number line
(Gay, all numbers starting from one, exclusive, to 5, inclusive) by the notation
(1,5). A range is a set, the collections of numbers in that range.
+t 2
oor 2 3 4 5 6 7 US]=freR|1<2<5}
Exercises
Determine whether each statement is true or fase. 1.9.11. The set of living species of the genus canis,
131 -eM
1.3.12 The set of United States Presidents from the Whig
parry.
1.3.13 The set of entrees at the dining hall tonight.
1.3.14 The set of pages in this book that the index refers
to under “cardinality”
Describe each of the following sets using set notation, in
terms of the other number sets (that is, do not use the
siven set tse),
13.15 W.
Use set notation to denote the following sets (look up
information as necessary).
1.3.16 [12,135),
214,_SET OPERATIONS
Set operations
In elementary arithmetic, we have two kinds of operations, The first kind,
including +, —,-, and +, all operate on numbers and produce another number
‘Their result can appear any place where a number can appear, including as the
operand to another operation. Thus we have
543 Be (48-13) +
‘The other kind of operation also operates on numbers but produces some-
thing which grammatically can be considered a sentence. In other words, it
does not produce another number, but a true or false value. =, >,and
# are all of this kind, The operator acts as the verb of the sentence.
=8 17> 1856 (54 4)-a1
The last of these happens to be false, but it still is a (grammatically) valid use
of the operation.
Similarly we have operations on sets, both those that make sentences about
sets and those that simply make new sets. Of the sentence-making variety,
there are two that we make frequent use of, = and C. If one set is completely
contained in another, that is, every element of the one set is also an element of
the other, then we say that the first is a subset of the second and use the symbol
Suppose A and B are sets. (As with other mathematical objects, we can use
variables to stand for sets. By convention, we use capitals.) Picture the subset
relation using a diagram like those from Section 1.1.
subset
We already declared what it means for two sets to be equal in Axiom 2.
Notice that A — B means the same thing as AC B and BC A taken together,
‘and this also implies that for any set A, AC A. If wemean BC A and B 4 A—
in other words, A has everything in B, but there is at least one element in A
that is not in B—then we say that 2 is a proper subset of A and write B.C A.
‘This is rarely an important observation.
In these cases we also call A a superset (or, if appropriate, a proper superset)
of Band write AD B or A > B, but we will not use these symbols very often,
either, Thus the main sentence-making set operations we are interested in are
Cand =.
13
roper subset
suparseeCHAPTER 1. SET
‘There are three basic operations to compute a new set given two other sets,
just as we have arithmetic operations for computing numbers from two other
numbers: union (U), intersection (A), and difference (-). Informally, the union
of two sets, AUB, is the set containing all clements of A and all elements of B.
‘The intersection of two sets, A B, is the set containing only those elements
that are both in A and in 11. The difference of two sets, A ~ B, is the set of
elements in A that are not elements of B.
Union
{1.2,9)U 284) = (42,3,4)
‘The set of elements that AUB={2|reAorre Bh {L2}0 (84) = (129.4)
are in either set. (2}0 0,23) = (23)
Intersection
11,2.3}92,8,4)
‘The set of elements that ANB={2|4¢Aandx = B} {1,2}0(8.4)
are in both sets. {12}00,2.3}
a ®
NK
Difference
(0,2,3)— 3.4) =
‘The set of elements that A-B={2|reAands¢ B) (1.2) Ga}
are in the first set but (2) 0.23) =
not in the second.
It is crucial to understand that these are not sentence-making operations but
set-making operations. A beginning student might take AM B to mean “sets A
and B overlap at some point.” 47 B is a noun phrase that describes the set,
that is the overlap of A and B, and it may very well be empty. To say that A
and B overlap, write ANB 4 0.
‘These diagrams with overlapping ovals that we have been using are called.
Venn diagrams Venn diagrams, named after English logician John Venn.
When sets are used to describe ideas, the context usually assumes a universal
universal et set, a set from which all elements under discussion come. For example, if the
“sets being discussed are {1,3,5} and (2,3,4,7,10), the universal set can be
assumed to be one of the number sets, pethaps Z or W. If the sets are things
like {«,b, an, q}, then the universal set may be the set of letters in the alphabet.
If-we are talking about the set of students registered for one course or another
ina given semester, the universal set is the set of students enrolled at the school.
Generically we use 2 to stand for the universal set, and it appears in a Venn
diagram as a box framing the rest of the picture.
‘The universal set concept allows us to define the complement of a set, which
is the set of everything that is (in the universal set but) not in the set. Formally,
=(2eu|r eX}
One could also say X = U — X, Some authors use X" instead of X to denote
complement.
x
Complement is a set operation just like union, intersection, and difference,
except that it is a unary (one-operand) operation, not a binary (two-operand)
operation. This is just how a negative sign takes only one operand, whereas a
minus sign takes two. As with arithmetic operations, these can be combined.
‘The shaded area below is X —(Y UZ).
u
14,_SET OPERATIONS
1412 ACC,
1413 RCCAR™
1414 4€C.
1415 QNT=0.
1416 4 <@-z.
1417 2—R-
1418 TUZC A.
1.4.19 All of the labeled sets we considered in Section
1.1 have an infinite number of elements, even
though some are completely contained in oth-
cers. (We will later consider whether all infinities
should be considered equal.) However, two re-
sions have a finite number of elements
a. Describe (both verbally and using the nota-
tion in this chapter) the region shaded IL How
‘many clements does it have?
b. Describe the region shaded [I How many
elements does it have?15. VERIFYING FACTS ABOUT SETS
[1.5] Verifying facts about sets
Let A = {1,2,3}, B= {3,4,5), and C = [5,6,7}. Notice
AU(BAC) = {1,2,3}U({3,4,5}7 (5,6,7})
= {L2.3}0{5)
= {2.3.5}
and
(AUB) (AVE) = ((1,2,3}U 3.4.5) ({1,2,3}U 5,6,7))
5} (1,2,3,5,6,7}
3A
3,5)
In other words,
AU(BNC) =(AUB)N(AUC)
Since there does not seem to be anything special about how we chose A,
B, and C, we might suspect that this formula holds true for any three sets. It
tums out that it is, and this is called the distributive law. Notice how similar
it is to the distributive law you learned in grade school: - (y+ =) == y+
r+ for x,y,z © R. The union operation is analogous—in this context, at
least—to multiplication and the intersection operation to addition. Much of
higher mathematics is about finding patterns that recur in ostensibly dissimilar
domains
Later in this course we will prove this and similar propositions about sets.
Informally we can demonstrate this using a series of Venn diagrams. First we
draw a diagram with three regions.
B a )
NN Se
‘Then we shade it according to the left side of the equation and, separately,
according to the right and compare the two drawings. First, shade A with [1
and BOC with EL
"7CHAPTER 1. SET
Drawing 1
)
Je
Note that AN (BC) has the darkest tint Il, indicating that it has been
shaded twice. With pencil and paper, you can shade one region with lines going
in one direction and another region with lines in the other direction. The inter-
section of those two regions will then have a criss-cross pattem. The double-
shaded region happens not to be important in this picture, though. We are
interested in the union operation, indicated by all the shaded regions together,
‘Now, in separate pictures, shade AU B with and AUC with
a a
Drawing 2 Drawing 3
A c 4 c
Put these two on top of each other, and the intersection of these two sets is
the region that is double-shade«
Drawing 5:
only the double-shade
from Drawing 4
Since the total shaded region in the first picture is the same as the double-
shaded region in the combined picture, we have verified the proposition. Graph-
, with a little narration to help, can be used for an informal, intuitive proof
‘As a second example, consider the claim
Wup-7-8
815. VERIFYING FACTS ABOUT SETS
Suppose a farmer has some cattle named Alvin, Beverley, Camus, Daisy,
Bade, and Gladys. Ler A be the set that are cows (Beverley, Daisy, and Gladys),
the rest (1) bulls. Alvin, Beverley, Camus, and Gladys are spotted; designate
them as set B.
‘The cattle that are bulls or spotted (or both) are Alvin, Beverley, Camus,
Eddie, and Gladys; that is AUB. The cattle that are cows but not spotted
(A~B) are just Daisy. The rest (AB) are Alvin, Beverley, Camus, Eddie, and
Gladys. In this example, it seems to work.
Now we will draw it. This time we must include the universal set in the
drawing.
Original
2a A-pO
7
UB any shade
19CHAPTER 1. SET
Exercises
Verify using Venn diagrams (with verbal explanationsas 1.5.7 AU(A~B) =A.
necessary). 158 AU(B-A)= AUB
BSE AUN B) =A. 15.9 (A— B)N (ANB) = 0.
182 Aud=u.
15.10 An(B-(AnB))
183 AU(BUC) = (AUB)UC.
184 An(BUC) = (An BLANC) 1s (AU
185 AnB=A~(A—P) 112 (AU(B—C)) 0B
186 (An€) - (CB) = AnBne. 1513 (BUC)- 4=(B-A)U(C- A)
1.6] Values, expressions, and types in ML
‘This text teaches diserete mathematics and functional programming together
for two reasons: so that you can transfer skills for writing proofs to writing
programs and vice versa, and so that we can model mathematical concepts on
computer. The programming language ML is chosen for its usefulness towards
these goals. The discrete math topics and the programming topics are as tightly
‘woven as possible, but we must lay out the basic threads of each topic stream,
first.
Now and then we will make some comments that are significant only to
students who have previous programming experience in a language other than.
ML. However, no such experience is necessary to acquire ML proficiency in this
study.
Although ML can be used to build stand-alone applications, we will assume
that the ML interpreter is running in interactive mode. This means the ML. in-
terpreter has been launched without a program to run, and the ML interpreter
itself gives a prompt to the user, who is also the programmer. The user enters
ML code, which the interpreter executes. ‘Thus we have a work-cycle of the
uuser-programmer entering an expression or declaration (we will define those
terms below), the interpreter evaluating it, and the interpreter displaying the
result,
Biography: Robin Milner, 1934-2010
Robin Milner was born near Plymouth, England, and was educated at Eton School and the
University of Cambridge. After his first experience with computer programing, he decided that
programming ys “inelegant” and that he “would never go near a computer” again, He later
changed his mind, or he changed programming.
‘Milner originally developed the programming language MI. as a metalanguage for his
‘automatic theorem-proving system Logic for Computable Functions. The language proved useful
enough to take on a lie of ts own, This and his Work on concurrency le to his winning the 199%
Turing Award. He died in March 2010.[17]1.6. VALUES, EXPRESSIONS, AND TYPES IN ML
I is crucial chat you acquire the basic vocabulary of ML programming. The
term value is primitive, so we will not define it, but, informally, values model
mathematical ideas. Examples of values include 5, 16, and 7.5, One of the
beauties of our approach to programming is that we will not be working with
just numbers all the time, so we will see values of all sorts of things. However,
‘numbers make the easiest examples to start with.
‘An expression is any construct in the programming language that the in-
terpreter can evaluate to a value. On one hand, a value is the result of an
expression; altemately, values themselves are trivial expressions if used in the
right context. A value used as an expression (or, the simplest expression which
evaluates to a certain value) is called a literal
‘That basic form used when interacting with the ML interpreter is
;
‘Try entering a literal. ‘Text that the user types into the prompt will be in
‘typexriter font; ML's response will be in slanted typevriter font. The-
at the beginning of the line is the prompr, not part of what the user enters
8;
val it = 5; int
Here is what ML’s response means: val is short for value and indicates that
the result value, not surprisingly, is §. 2 is a variable, and int is the type of
the value—we will discuss all these later.
We can make more interesting expressions using mathematical operators.
We can enter
-7-2
val it = 5: int
Note that this expression itself contains two other expressions, 7 and 2.
‘Smaller expressions that compose a larger expression are called subexpressions
of that expression. ~ is an operator, and the subexpressions are the operands of
that operator. + means what you would expect, + stands for multiplication, and
~ (tilde) is used as a negative sign (having one operand, to distinguish it from
-, which has two); division we will discuss later. To express (and calculate)
67-44% 18, enter
67 +447 43,
val it = 18: int
au
value
expression
literal
subexpression
operator
operandCHAPTER 1. SET
itemuifer
eywords
‘Variables in ML work just as they do in mathematics (though subtly different
from most programming languages). ‘The variable it is where ML stores its
latest result, unless you tell it otherwise. We can use a variable as an expression.
~ att 3;
val iv = 18: ine
‘To use a name other than it, imitate the interpreter’s response using val,
the desired variable, and equals, something in the form of,
val = ;
val x= 5;
val x=: int
An identifier is a programmer-given name, such as a variable, ML has the
following rules for valid identifiers:
1. The first character must be a letter. (Certain kinds of identifiers begin
‘with an apostrophe followed by a lewter)
2, Subsequent characters must be letters, digits, underscores, or apostto-
phes.
3. Identifiers are case-sensitive.
‘Some character sequences that fit the criteria above already have meaning
in the language, words like val and int. These are called keywords, and they
‘may not be used as identifiers.
It is convention to use mainly lowercase letters in variables. If you use
several words joined together to make a variable, capitalize the first letter of
the subsequent words.
= val mimutesInHour = 60;
val minutesInour = 60: int
= val hoursInDay = 24;
val hoursInDay = 24 ; int
- val daysInYear = 365;
val daysInYear = 365 : int
= val minutesInYear =
= wimutesInHour * hoursInDay « daysInYear;1.6. VALUES, EXPRESSIONS, AND TYPES IN ML
val minuvesTnYear = 525600 : int
~ val minutesInCentury = minutesTnYear + 100;
val minutesInCentury = 52560000 : int
So far, all these values have had the type int. A type is a set of values that are ope
associated because of the operations defined for them. ‘Types also categorize
values by how they are stored in computer memory, but that will not be a
concern for us. We will use sans serif font for types. Understanding types is
crucial for suecess in programming,
‘Types model the mathematical concept of a set, but imperfectly. MI. does
not provide a way to use the concepts of subsets, unions, or intersections on
types. We will later study other ways to model sets to support these concepts.
Moreover, the type int is not the same thing as the set Z, although it corre-
sponds to that set in terms of how we interpret it. The values (elements) of
int are computer representations of integers, not the integers themselves, and.
since computer memory is limited, int comprises only a finite number of values.
On the computer used to write this book, the largest integer ML recognizes is
1073741823, Although 1,073,741, 824 € 2, itis nota valid ML int
= 1073741824;
Error: int constant too large
ML also has a type real corresponding to R. We will not use real much, but
itis a good example of a second type. The operators you have already seen are
also defined for reals, plus / for division
~ 74.73;
val it = “4.73 : real
= 7.1 4.8 / 63.25
val it = 7.02405063291 : real
Tangent: Comprise
Comprise is one of those words commonly used in ways that annoy English purists. H.W. Fowler says, “The common
se of comprise as a synonym of compose or constitute isa wanton and indefensible weakening of our vocabulary”
(10). Strunk and White say, ‘A 200 comprises mammals, reptiles, and birds. But animals do not comprise a 200—they
constitute a 200"(32]
you care about such things, then just remember a set comprises its elements, and elements constitute a set.
23CHAPTER 1. SET
‘The difference between the type real and the set IB is even more striking
than the difference between int and 2. Since real is finite, it not only leaves out
numbers too big or too negative, but also an infinite number of numbers along
the way. For example, ML has a pre-defined value for 7.
= Math.pi;
val it
3. 14159265359 : real
‘That value is certainly not an exact representation of x. Instead, it is the
value of type real that is closer than any other real to the exact value of 7.
For another limitation of using int and real to represent 2 and IR, observe
this result
= 5.3 - 0.3;
val it = §.0: real
5.0 has type real, not type int. int is not a subset (or subtype) of real, and
5.0 is a completely different value from 5. It is better to think of int and real
as being separate universal sets, rather than subsets of the universal set of all
numbers.
A consequence of int and real being unrelated is that you cannot mix them
in arithmetic expressions. English requires that the subject of a sentence have
the same number (singular or plural) as the main verb, which is why it does not
allow a sentence like, “Two dogs walks down the street.” This is called subject-
pe agreement verb agreement. In the same way, these ML operators require type agreement
That is, +, for example, is defined for adding two reals and for adding two ints,
but not one of each. Attempting to mix them will generate an error.
- 7.345;
Error: operator and operand don’t agree [Literal]
operator domain: real * real
operand real # int
in expression: 7.3 + §
‘This rule guarantees that the result of an arithmetic operation will have the
same type as the operands. It also complicates the division operation on ints.
We expect that 5 +4 = 1.25~as we noted in Section 1.1, division takes us out
of the circle of integers. Actually, the / operator is not defined for ints at all.
- 5/4;
Error: overloaded variable not defined at type
symbol: / type: int
241.6. VALUES, EXPRESSIONS, AND TYPES IN ML
You will have to revert to fourth grade to understand ML's view of division
oon integers. Instead of producing one (real number) result (7+ 3 = 23),
division produces two (integer) results, the quotient and the remainder (7 :
3 = 2R1). ML computes the quotient—thar is, with the result you would
otherwise expect rounded down to the nearest integer, or with the remainder
discarded—with the operator div. This is called integer division. The remainder inceger dviion
is calculated by the modulus or mod operator, nod.
‘mod operator
- 5 div 3;
val it = 1; int
- 8 nod 3;
val it = 2: int
If there is need to mix reals and ints in the same computation, the following
can be used to convert between the types.
Converter converts from to _by
real int Teal appending a 0 decimal portion
round() real int conventional rounding
floor) real int rounding down
ceil real int rounding up
rune) real int throwing away the decimal portion
For example,
= 18.3 / real(6);
val it = 2.55 : real
~ erune(16.3) aiy 6:
val iv = 2: int
Not everything in this section is crucial for you to remember. In fact, we
will not use real very often in this text, and you will be hard pressed to find any
occurrence of the trunc() converter The point here is to understand how ML,
like almost any programming language, categorizes values into types, and how
that affects the way we use them. In the next sections we will learn other kinds
of types and learn to create our own.
Now, without looking back, what do the terms value, expression, literal, iden-
tifier, and ype mean? Make sure you both understand what they are and
can articulate a precise definition. Do not leave this section until they are
mastered.
25CHAPTER 1. SET
Exercises
1.6.1 Is coi1(45.2) an expression? Ifnot, why not? If
so, what is its value and what is its type? Would
ML accept ces1(18)? Why ar why not?
What Is the difference between trunc() and
ficor()? Give an example of an actual param.
eter for which they would produce different re
1.62
16.6
actually 365.25 days in a year, and so the variable
dayeInYear should be of type real. Your final an-
swer should still be an int.
‘Mercury orbits the sun in 87.969 days, Calculate
how old you will be in 30 Mercury-years. Your
answer should depend on your birthday (that is,
sults. do nor simply add a number of years to your age),
1.63 Which of the following are valid ML identifiers? but it should be an int
(a) bello
(b) points scored
(©) points'scored
(@) pointsscor
(©) veroctey
© -welecity
(g) velocity12
(h) 12veL0city
1.64 Compute the number of second in a year, similar
to how we computed the number of minutes. You
may assume 365 days in a year.
Redo the computation of the number of seconds
in a year, taking into consideration that there are
165
1.67
168
1.69
Use ML to compute the circumference and area
of a circle and the volume and surface arca of
fa sphere, first each of radius 12, then of radius
1278.
‘Store the values 4.5 and 6.7 in variables standing
for base and height, respectively, of a rectangle,
and use the variables to calculate the arca. Then
do the same but assuming they are the base and
height of a tangle.
You have a distance 185 long that you wish to
cover with tiles & of an inch long. You cannot
break the tiles; they must be used in whole. Use
‘ML to determine how many tiles will fir and how
‘much length will be left over.
[1.7] Characters and strings
Processing text has always been an important domain of computer applications.
Consider how much computer usage consists of using word processors, not
to mention email, blogs, and Twitter. Our first examples of types other than
number types are those used in manipulating text.
A character is a display symbol—a letter, a digit, a punctuation mark, ete.
ML represents these as values using the char type. A char literal is made by
enclosing the character in quotation marks and prepending a pound sign.
character
= tat
val it = #a" : char
‘Some characters are hard to make. For example, the quotation mark symbol
would confuse the interpreter because it would not differentiate berween the
intended char value and the opening and closing quotes.
eee1.7._ CHARACTERS AND STRINGS
character constant not length 1
‘To make certain characters, ML has two-symbol special codes, each begit
ning with the \ symbol: \" for the quote sign, \t for the tab character, \n for
the newline character, and \\ for the backslash character.
Every character has a numeric code associated with it (based on the ASCII
or Unicode character set). You can convert a character to the int of its numeric
code using ord, and you can obtain the char of a specific code using chr
~ ora(#"q")
val it = 113: int
= chr (114);
val it = #"r" : char
What we see is that alphanumeric characters, like almost all other kinds of,
information stored and processed by computers, are represented as numbers.
One use of this is enctyption—suppose we want to replace each letter ina text
with the letter that comes three positions later in the alphabet.
~ val cc = sp";
val ce = #"bY 2 char
= val d= chr(ord(ce) + 3);
val d= #"e" : char
A string is a sequence of characters. ML represents them with the string suring
type. A string literal is like a char literal except that many characters may appear
between the quotes and they do not begin with a pound sign.
~ "nelle"
val it = "hello" : string
= it 7" goodbye":
val it = "hello goodbye” : string
A string may have any number of characters, including zero or one.
aCHAPTER 1. SET
val ie =": string
val ip = "a": sering
Notice that the value #"a" of type char isa different value from "a" of type
string, Values of type char can be converted to strings (of length 1) by the
function str. Integers can be converted using Int. toString.
~ etrGi%q");
val tr = tq": string
~ int toString(32);
val it = *92" : string
‘The following summarizes some operations on strings (supposing variables
‘and b have type string and variables a and m have type int)
ace Concatenate or chain two strings together to make a larger string.
sizo(a) Compute the number of characters in a string.
String.sub(a, a) Find the character at position a (counting from 0).
substring(a, a, m) Compute the string made from the w characters starting in position a.
= val s = "Live Free";
val s = "Live Free" : string
= val t = "or Die";
val t = "or Die" : string
val it = "Live Freeor Die" : string
Cops, we forgot the space between “Free” and “on”
-val stesc un
t
val st = "Live Free or Die" : string
281.7._ CHARACTERS AND STRINGS
~ size(st);
val it =
~ String-sub(st, 5);
val it = 9"
char
~ substring(st, 5, 4);
val it = "Free" : string
= sizo(it);
val it = 4: int
Exercises
1.7.1. Suppose the variable c= holds a char Cand assume
it isa lowercase letter), the variable n holds an
int, and we want to produce the char that isn po
sitions in the alphabet away from ce. The exam:
ple given in the text (chr(ord(ce) + n)) would
not always work, because we may run off the end
ff the alphabet. What we want in that ease is to
‘wrap around to the beginning of the alphabet—if
ce isy, then one position away is z, but two po
sitions ‘away is a, ee positions away is b, ete
Write an ML expression to compute the desized
character. (Hint: You will need to use the nod op-
erator, First, think about how you would do this if
‘had numeric code 0. However, a does not have
‘coe O—fix up your solution to deal with a's code
as an offset.)
1.7.2 Suppose the variable LongHlane is set to the string
Light amplification by stimulated
eaiesion of radiation
173
174
29
Use ML string operations to produce the string
"Laser" from it
Suppose the variable x is set to the string
brother-in-lay
Use MI. string operations to produce the string
‘prothers-in-Lav" from it,
Suppose the variable y is set to the string
asdfghjicl;
Use ML to determine how many letters would be
left over if could divide the string into segments
of four letters each. (The answer is 1: the charac:
ters 1; are left over ater dividing the sting into
asdf and ghjle)CHAPTER 1. SET
cardinality
saint
us.
Whig party
Students enrolled in
Diserete Mathematics at
9:15
[1.8] Cardinality, disjointness, and partitions
Having introduced the basics of the ML programming language, we return to
‘mathematical concepts of sets in this section and the next, As we pursue these
‘two streams of ideas, they will illuminate each other more and more. We have
already seen how sets are used to describe ML types, and in the next chapter
‘we will see other means in ML for modeling sets. Meanwhile, we will increase
the sophistication of the concepts and terminology we have to talk about sets,
as well as introduce new features of the ML programming language.
‘The cardinality of a finite set is the number of elements in the set. This is
symbolized by vertical bars, like absolute value. For example, |{violin, cello
viola, bass}| — 4, or |W —N| = |{0}| = 1. This is an informal definition, A
careful definition of cardinality is surprisingly complicated, as we will see in
Section 7.9. There is no reason, however, to avoid using the term until then,
since itis pretty clear intuitively.
It is important to understand that this definition applies only to finite sets
It does not allow you to say, for example, that the cardinality of 2 is infinity.
Instead, say that a set like 2 is infinite. Cardinality is defined only for finite sets
for our current purposes. At a later point, we will explore how to extend the
notion of cardinality to infinite sets—it is not an easy task, bringing up certain
interesting problems.
If we have two sets from the same universal set, we say they are disjoint if
they have no elements in common. Formally, sets A and J? are disjoint if their
intersection is empty,
ANB=6
‘Some examples of disjoint sets:
R N
USS, Presidents who later
became Chief Justice of
the Supreme Court
Presidents from the
‘Students enrolled in Art
Survey at 9:15
Tangent: Cardinal and ordinal numbers
Cardinal numbers are the words one, cwo, three, ..., which are used to express quantity (from Latin card,
‘hinge, think “something fundamentally important"). Ordinal numbers are the words fis, second, third, ...,
‘hich are used to express position, such asin a line or Sequence (from Latin oro, “line” or *row”).
Tokeep these stright, just remember that sets are unordered—theve is no “third” element—but finite sets
do have a cardinality.1.8. CARDINALITY, DISJOINTNESS, AND PARTITIONS
Ina Venn diagram, if sets A and B are drawn so that they do not overlap
(@s seen on the left), then one can be certain that they are disjoint. However,
just because two sets are drawn with an overlap does not mean that they are
necessarily nor disjoint. Regions of a Venn diagram do not indicate size of the
represented set, and the region of their overlap could simply be empry.
OO] [
Disjointness will come up frequently. We also have an extended version of,
this concept that is useful when we are dealing with a larger number of sets.
Consider the set of single-serving items at a bakery:
5 = { muffin, cupcake, scone, cookie, brownie, tart, donut, bagel }
From this we could have a variety of sets:
A Items that are round, viewed from above { muffin, cupcake, cookie, donut, bagel)
B Items with exposed filing {tare }
C Items considered relatively healthy { muffin, bagel }
Are these sets disjoint? Notice A) B = 0, BC = 0, and most importantly
AN BAG = 0. However ACC # 0. What does it mean for three sets to be
disjoint? “These three are disjoint if taken together, but not if we consider all
pairs
‘To clatify this terminology, we say that a set of n sets from a universal set
are painwise disjoint if no two of them have any overlapping elements; you can pairwise sone
pick any two distinct sets from the set of sets, and they will be disjoint. The
following set of sets is pairwise disjoint:
Items roughly-mushroom shaped _{ muffin, cupcake }
Items roughly cylindrical { cookie, tart }
Items torus-shaped { donut, bagel }
‘The concept of pairwise disjoint naturally leads to that of a partition. If pariion
X isa set, then a partion of XX is a set of sets (Xy,Na,...,Nu} such that
Xi, Xa... Ny are pairwise disjoint and Xy UNyU,..UXy = N. Intuitively
a partition of a set is a bunch of non-overlapping subsets that constitute the
31CHAPTER 1. SET
entire set. If we add { scone, brownie } to the three sets mentioned above, then
those four sets make up a partition of the set of single-serving bakery items.
Putting that in the universe of all bakery items, we can illustrate these sets this
From Section 1.1, T and A make up a partition of lk. One partition of
is the set of evens and the set of odds (these two sets together make one
partition). {2 {0)..} is also a partition. Or consider the set of students in
your class. If we grouped students together by majar (say, the set of computer
Science majors, the set of math majors, the set of physics majors, the set of
music majors), would these sets constitute a partition? Not if the class included
double majors or undecided students. A double major would be a member of
‘more than one set, violating the fact thatthe sets must be pairwise disjoint. An
‘undecided student would not be a member of any set; that would violate the
fact that the union ofall the sets must be the original set.
Exercises
1.8. What is the cardinality of (0,1,2,....2)?
1.82 Use Venn diagrams (supplemented with verbal
explanations, as necessary) to demonstrate that
(A-B)n(B—A) =O; thatis, A~Band B—A
are disjoint
1.83 Onemight be tempted wo think| AUB] = |A]-+),
but this is not true in general. Why not? In
mathematics, “in general” means “always.” Un
der what special circumstances is it tue? (As:
sume 4 and Bare finite.)
1.84 Is |A~ B| = [4] ~ |B] tue in general? If s0,
explain why. If not, under what spectal eireum-
stances isit true? (Assume A and Fare finite.)
1.8.5 Consider the sets {1,2,3}. (2,34). {34,5}. and
{45,6}. Notice that
{1,2,8) 742,34} {34,597 {4,5,6)
Are these sets pairwise disjoint?
1.8.6 Describe three distinct partitions of the set 2,
apart from the partitions given in this section,19.
CARTESIAN PRODUCTS
[1.9] Cartesian products
In earlier mathematical experiences, you used the number sets we talked about
at the beginning of this section not only to enumerate and measure, but also for
labeling. Consider a classroom full of desks, with each position named by what
column and row itis in, or consider how points in the real plane are identified.
RRA
BARA on
RRA
RRA
Re TH
“The set of desks (or names for the desk positions) and the set of points (or
labels for those points) are built from other sets. Specifically, each element has
two components, each component drawn from a set we have already talked
about.
An ordered pair is two elements (not necessarily ofthe same set) written in
a specific order. Suppose X and ¥ are sets, and say x © X andy € Y.. Then we
say that (x,y) is an ordered pair over X and ¥. Two ordered pairs are equal,
say (x,y) = (w,2) if = wand y = =, An ordered pair is different from
set of cardinality 2 in that itis ordered—and that the items in a pair may be
drawn from different universes, Moreover, the Gartesian product (named after
Descartes) of two sets, X and Y, written X x Y and read “X eross Y,” is the
set ofall ordered pairs over X’and Y. Formally,
{O00 0
Xxy
(ew) |e X and y © ¥}
‘The real plane from analytic geometry is doubtless the example of Cartesian
product most familiar to you, and it is written R x R. Applying our methods
of set theory, we recognize that the real plane is really just a set, like the big
number sets, whose elements are points, or pairs of real numbers, depending.
‘on whether it is more convenient to think geometrically or algebraically.
Generally we will be interested in more restricted sets of pairs, that is, sub-
sets of the Cartesian product. Thus a Cartesian product will be taken as a ui
versal set in most contexts, and the component sets of the product will usually
be universal sets in their contexts.
We can extend the idea of pairs to chat of triples, quadruples, or more gen-
erally, n-tuples, or just tuples for short. The notation for Cartesian products
3
ordered pir
Cartesian produce
plesCHAPTER 1. SET
extends naturally to higher orders: For sets A, B, and C, tuples of elements
from them form the set Ax B x C.
Caneesian products are not only for sets of numbers, however. Consider how
sets and tuples can be used to describe a paper doll set.
Qo
cs %
/)
i}
\
\
i
AY P F
i =
)
OG
‘We have a set of tops, { £8, G, A}; a set of bottoms, {MMF}; ana
set of headwear, { ©, 4). Picking one from each set makes an outfit, which
isan element of { £3, ©, {3} x (oN xp0.0).
Biography: René Descartes, 1596-1650
Descartes was a French mathematician, philosopher, and mercenary soldier. His
greatest contribution to mathematics is analytic geometry, by which geometric entities
fre described algebraically —hence the familar coordinate system named for hi,
Do you hate morning classes? Descartes is your patron saint, He did some of his
‘most productive thinking while lying in bed until late the morning—in fact, an
unconfirmed story suggests he invented the coordinate system by watching a fly on 3
his ceiling and considering how its two-dimensional position could be described by
horizontal and vertical coordinates. He died while in the service of Catherine of
Sweden, a young queen who demanded philosophy tutoring at 5:00 in the morning.
2)1.9. CARTESIAN PRODUCTS
‘Tuples are an important class of types in ML. Tuples appear just as they do
in mathematical notation, and the components may be of any type, including
lists and other tuples.
- 6;
val i = (6,4) + ant + ant
~ (2,"discrete", 8.3);
val 1 = (2,"dlecrote", 8.3) + int + string + real
‘The type int * int corresponds to the set Z x 2.
You can make tuples of any other type—even tuple types. This next one is a
tuple whose last component is itself a tuple.
~ (5.3, "functional", (5, #"x"));
val it = (6.3, "functional", (5, #"x"))
: real * string + (int * char)
‘To understand complicated types like this, we can analyze them by subex-
pressions. This demonstrates why the expression has this type.
ep emerson Sf)
To
i
veal sing (at * cha)
‘The operations #1, #2, etc, retrieve the respective element from the tuple.
Continuing the above example,
= #1(#3(4t));
val it = 5; int
As we will see later, these operations are rarely necessary, Context will
provide other, more convenient mechanisms for retrieving the components of a
tuple,
35CHAPTER 1. SET
Exercises
In Exercises 1.9.1-1.9.3, describe the given Cartesian
product (by listing all the elements).
19.1 (1,2) x (1,2)
1.9.2 {abe} x {abe}
1.9.3 (a.besd} » {1.2}
1.9.4 IFA and B are finite sets, what is |4 x B] in terms
of [al and |B)? Give an intuitive argument why
{you think your answer is correc.
1.9.5 Based on our description of the real number plane
asa Cartesian product, explain how a line can be
interpreted asa set.
1.96 Explain how C, the set of complex numbers, ean
be thought of asa Cartesian product.
1.97 Any rational numiber (an element of set @) has
two integers as components. Why not revrite
fractions as ordered pairs (for example, }as (1,2)
tnd 4 as (3,4)) and claim that @ can be thought
of as'Z x 2? Explain why these two sets cannot
be thought of as two different ways to write the
same set. (There are atleast two reasons.)
Which of the following are a partition of R x R? For
‘those chat are not, why not?
1.10
‘We have seen types that model the sets of integers, real numbers,
1.9.8 {A,B} where A isthe set of points above the line
y = Se +2, and B is the set of points below the
line,
1.9.9 (A,B) where A is the set of points in the first
(upper right) quadrant, and B the set of points
not in the fist quadrant
1.9.10 (A,B,C) where is the set of points that are on
the x-axis, isthe set of points that are on the y-
axis, and C'isthe set of points that are on neither
1.9.11 Consider entering a cafeteria with a variety of
food lines: salad line, an entrée line, a bev-
‘erage line, etc, each having several options. Sup-
pose you plan to take one item from each line.
Explain how your meal is a uple, and thatthe set
‘of possible meals is a Cartesian product.
‘Analyze the type ofthe following expressions.
1912 (3, 6.4)
19.13 (3, Gx", #yD, 12)
19.14 (tdiscreter, #2",
1.9.15 (discrete, (tn, wa", HE", AMR)
19.16 (3, @, G4, (@, 49), 139, 7, 9)
Making your own types
play char-
acters, and sequences of display characters, and tuples combining any of these.
‘We now turn to making our own, arbitrary types. Suppose we want to model
daxacype
the set of tree genera, We could define the following datatype:
= datatype tree = Oak | Elm | Maple | Spruce | Fir |
. Pino | Nilloy;
datatype tree = Elm | Fir | Maple | Oak | Pine | Spruce | Willow
What we are saying is that we have seven items (oak, elm, mople, spruce,
{fis pine, willow) that constitute a set, rree, expressed in ML. by naming a type
‘and listing the values of that type. The name of the type (in this case tree) and
the values of that type (in this case there are exactly seven values) can be any
identifiers, but by convention the name ofthe type is lowercase like an ordinary
variable and the first leter of each value is capitalized.
361.10, MAKING YOUR OWN TYPES
Since this type has no operations defined for it (until you learn to compose
your own), there is little we can do with datatypes yet. However, observe that
their values can be stored in variables, as with any other type
~ val t = Maple;
val t = Maple : tree
-t
val it = Maple : tree
Here are two more examples.
~ datatype vegetable = Carrot | Zucchini | Tomato |
- Cucumber | Lettuce;
datatype vegetable = Carrot | Cucumber | Lettuce | Tomato |
Zucchini
= datatype grain = Wheat | Oat | Barley | Maize;
datatype grain = Barley | Maize | Oat | wheat
“To extend this, suppose we want to model plots of ground. These plots can
be used to grow trees, vegetables, or grains, or they may be empty (we will
call such plots groves, gardens, fields, and vacant plots, respectively). We want
to model this with datatype as well, but we need to capture the fact that a
garden is not just a garden, its a garden of something. For this, you can specify
the values of a datatype to be containers for another value. In that case, we say
that the datatype value is carrying “extra information.”
= datatype plot = Grove of tree | Garden of vegetable |
- Field of grain | Vacant;
datatype plot = Field of grain | Garden of vegetable |
Grove of tree | Vacant;
‘This indicates that Garden by itself is not a value, but rather we need a
vegetable value to complete it.
~ Garden (Lettuce) ;
val it = Garden Lettuce : plot
7CHAPTER 1. SET
= Garden Zucchini) ;
val it = Garden Zucchini : plot
~ Fiela(oat);
val it = Field Oat : plot
Garden (Lettuce) and Garden (Zucchini) are different values (which the
‘ML interpreter displays as Garden Lettuce and Garden Zucchini —we think
the parenthesized version is clearer). Now that we have seen this, we can
describe formally that one makes a datatype by giving the name of the datatype
‘constructor espresion followed by one or more constructor expressions:
datatype = | ... | ;
A constructor expression indicates the form that a value of the datatype can
take, The form is an identifier followed optionally by the type of any extra
information, introduced by the keyword of:
of
(One way to extract the extra information from a datatype value is to declare
variable for it implicitly.
~ val glen = Grove(ak) ;
val glen = Grove Oak : plot
~ val Grove(ohatTree) = glen:
val vharTree = Oak : tree
‘The second vai declaration may look strange (but pethaps all of ML still
looks strange to you). The variable we are declaring there is whatTree. The
declaration is implicit in the sense that the variable is put in the context of the
constructor expression Grove, We are saying, ‘Assuming glen is a Grove of
some tree, let vhatTree be that tree.”
‘The type of the variable glen is plot, which means that in theory it could
have been a Field, a Garden, or Vacant. You will get into trouble if you do an
implicit declaration using a form that happens to be wrong:
= val Field(shatGrain) = glen;
38uneaught
1.10, MAKING YOUR OWN TYPES
exception Bind [nonexhaustive binding failure)
Unfortunately, the error messages given by typical ML implementations are
not very helpful for beginners.
‘When we combine datatypes with tuple types, we can make datatype values
that contain several pieces of extra information, and from there we can make
types to capture complicated real world information. Suppose a restaurant
offers value meals for which customers can pick an entrée, a side, and a bev-
erage. The entrée can be either make-your-own sandwich or make-your-own
pasta. These datatypes model the basic components (we omit the interpreter's
response for brevity)
datatype
datatype
datatype
datatype
datatype
datatype
datatype
bread = white | MultiGrain | Rye | Kaiser;
spread = Mayo | Mustard;
vegetable = Cucumber | Lettuce | Tomato;
doliMeat = Han | Turkey | RoastBoof;
noodle = Spaghetti | Penne | Fusilli | Genelli;
sauce = Posto | Marinara | Creany;
protein = MeatBalls | Sausage | Chicken | Tofu;
‘An entrée, then, is a sandwich or a pasta, and each of those options needs
tuple of elements chosen from the ingredients. Finally, a meal is a tuple over
the set of entrées, sides, and beverages.
davatype
entree =
Sandvich of bread + spread + vegetable + delilleat
| Pasta of noodle ¥ sauce + protein;
datatype
datatype
datatype
datatype
salad = Caesar | Garden;
side = Chips | CarrotSticks | Salad of salad;
overage = Vater | Coffee | Pop! | Lexonade | IceTea;
neal = Meal of entree + side + beverage;
Now we can make meals.
~ Moal(Sandvich(MultiGrain, Mustard, Lettuce, Ham),
= Chips, IcoTea);
val it =
Meal (Sandwich (MultiGrain, Mustard,Lettuce, Ham),
Chips, IceTea) : meal
~ Meal (Pasta(Fusilli, Creamy, Chicken), Salad(Caesar), Pop);
val it =
Meal (Pasta (Fusilli, Creany, Chicken),
Salad Caesar,Pop) : meal
1m fom che Midwest, and Ti callit pop if want to,
39CHAPTER 1. SET
Asa final example, we can use a datatype to do something like a union of
int and real:
~ datatype number = Int of int | Real of real;
datatype aunber = Int of int | Real of real
= Int (5);
val it = Int 5
= Real (5.3);
val it =
munber
Real 5.3 : number
“This is not a perfect solution, though. Int (5) and Real (6.0) are still differ~
cent values. Nevertheless, students who have programmed in an object-oriented,
Janguage like Java should notice the similarity between this and subtyping.
One note on terminology. In ML, datatypes constitute a certain kind of
programmer-defined types. The term datatype, however, is sometimes used in
‘computer science as a synonym for type. The kinds of types made using ML’s
datatype construct are sometimes called enumerated types or variant types.
In F# and OCaml, these types are made using the keyword type instead of
datatype.
Exercises
1101
1.102
1.103
Finish the following datatype book so that it has
ata constructors for various kinds of books (fic
tion, reference book, ...), each with string extra
information, used for the title and other informa
tion (such as author, number of pages, ete) where
appropriate.
datatype book
( author, title, pages +)
Novel of string * string * int
1
Make a datatype periodical that has data construc:
tors for various kinds of periodicals (newspaper,
magazine, academic journal, ...), each also with
extra information forthe ttle
Make a datatype recording that has data construc
tors for various recording media or formats (CD,
DVD, BluRay ...), each also with extra informa
tion for the title and running time.
1104
110.5
1.106
1.10.7
Finish the following datatype libraryltem so that
it has data constructors for various items in the
library, using your solutions in Exercises 1.10.1
1.10.3 for extra information
datatype LibraryTtem = Book of book |...
‘Make a datatype element that has data construc:
tors for certain chemical elements
‘Make a datatype ion that has data constructors for
cations and anions, using your solution to Exer
cise 1.10.5 for extra information; also include the
‘charge (resulting from the number of eleetrons
gained or lost)
Make a datatype molecule that has extra informa
tion about elements and their number of occur
rences in the empirical formula, Restrict this to
molecules with only two elements, such as am
monia (NH,), methane (CH,) and water (H,0).1.11. MAKING YOUR OWN OPERATIONS
1.11) Making your own operations
Modeling information by making your own types is only half of programming.
You must also do things with the values of those types. In these next two
sections we will learn how to write new operations, both for types that already
exist in ML and for our own types.
ML will reject an expression containing an unbound variable.
- x43;
Exror: unbound variable or constructor: x
However, x + 3 is not completely without meaning. It could denote the
process of adding 3 to a given , whatever it may be. In that case, we should
encapsulate the expression in a function that indicates that + is an independent
variable or parameter. We will study functions carefully in Chapter 7, but from
your previous mathematical experience, you know we write
S(e)= 248
to define such a function, if we wish to cal it f.
‘Another way to look at this is that we are generalizing from a specific case,
say 5 + 3, by replacing a specific value, say 5, with a parameter—we are pa:
rameterizing the expression. One way to look at a function, then, is that it is a
parameterized expression.
In MEL, you define a function much like the way you dectare a variable.
In either case, we are associating an expression with a name (the name of
the function or the name of the variable), but in the case of the function, the
expression is parameterized. For functions, we use the keyword fun in place of
val.
fun () = ;
‘The application of a function in ML looks exactly as it does in mathematical
notation.
~ fun £6) = x + 3;
val £ = fm: int > int
- 48);
val it = 8; int
aL
parameter
pplicationCHAPTER 1. SET
‘tual parameter In the application above, § is called an actual parameter since itis the value
substituted in for the parameter x in the function. To distinguish from actual
{formal parameter parameters, we call x a formal parameter. Notice that a formal parameter is a
kkind of variable; an actual parameter is an expression. A function application
is an expression, too.
‘The interpreter’s response to the function declaration was “Val f = fn: int,
> int.” Parts of this will not make sense until a later chapter, but int -> int
‘means that this function takes an int and returns an int. Functions may take
any number of parameters.
= fun mul, y) =x ¥ ¥5
val mul = fn: int ¢ int —> int
= aul (3, 16);
val it = 48: int
MIL has an interesting facility which allows you to give a different function
body for specific parameters. For example, the following function is undefined
at x = 1—it has point discontinuity because the denominator is 0.
2)
We can “fill-in” that point discontinuity by giving an explicit,
nition for the case of = 1
ser { a MEE!
otherwise
lifferent defi-
(Actually, the way we have done this, the function still has discontinuity at that
point, only now the function is at least defined everywhere.) In ML,
21.11. MAKING YOUR OWN OPERATIONS
~ fon £(1) = 0
= 1 f@) sere) div @- 0;
val £ = fn : int > int
- 20);
val it = 4; int
= 40;
val ip = 0: ant
= £2);
val ip = 3: ant
‘This style is called pattern-matching because we give a list of patterns de-
scribing what the actual parameters may look like (1, a very specific pattern,
and x, a completely wild card pattern), and when the function is applied, the
function definition of the first pattern that matches is used.
When we saw datatypes earlier, we noted that we did not yet have any
‘operations for them. We now can define our own operations using functions
Pattern-matching is a necessary tool for writing functions on datatypes.
Suppose we want to write a program that will predict the height of a tree
after a given number of years. The prediction is calculated based on three
pieces of information: the variety of tee (assume that this determines the tree's
growth rate), the number of years, and the initial height of the tree. Obviously
this assumes tree growth is linear, as well as making other assumptions, with
nothing based on any real botany. So, supposing that a tree's genus can be used
to determine growth rate (say, per month), we write
~ fun grovthRate(EIm) = 1.3
| growthRate (Maple) = 2.7
| growthRate(Oak) = 2.4
| growthRate(Pine) = 0.4
i
i
i
grouthRate(Spruce) = 2.9
growthRate(Fir) = 1.1
grouthRate(Willoy) = 5.3;
val grovthRate = fn : treeGenus -> real
How much growing the tree does depends on how much of the year it grows.
Let us assume that broadleaf (usually deciduous) trees grow for half a year and
1s (almostall evergreen) grow the entire year. Thus we need a function to
re each genus as either broadleaf (actually division angiospermae, which
includes all flowering plants) or coniferous (division pinophyta)
8
patter matchingCHAPTER 1. SET
= datatype treeDivision = Broadleaf | Coniferous;
datatype treeDivision = Broadleaf | Coniferous
= fun growingMonths (Broadleaf) = 6.0
= | growingMonths (Coniferous) = 12.0;
val growingMonthe = fn : treeDivieion -> real
- fun division(Pine) = Coniferous
= | division(Spruce) = Coniferous
| division(Fir) = Coniferous
| division(x) = Broadleaf;
val division = fn: tree -> treeDivision
‘Now, the function we are interested in:
= fun predictHeight (genus, initial, years) =
. imitial + (years * growinglonths division(genus))
+ growthRate(genus) );
val predictHeight = fa: tree * real * real -> real
Notice that a function can take any number of parameters. Actually, that is
not true, A function takes exactly one parameter, but that parameter may be a
tuple type. The function above has tree * real * real as its parameter type.
For our next example, suppose a farmer has a system for crop rotation,
‘Most plots go through a cycle of being a wheat field one year, followed by a
tomato garden, then a carrot garden, and then a year lying fallow as a vacant
plot. He has a few plots which alternate between being maize fields and lettuce
gardens, His one cucumber garden does not need to be rotated. He rarely
‘grows barley or oats, but when he does, they are rotated to zucchini, and then
vacant (after which they would go into the wheat-tomato-carrot cycle). Any
groves, of course, do not rotate.
Picture this system with the following diagram describing how plots rotate.
“oF
mM Sa. Ff ™
casunber a uci
baley aro
‘This function, when given a current use for a plot of land, determines the
use of that plot for next year,
“41.11. MAKING YOUR OWN OPERATIONS
rotate(Vacant) = Field (Wheat)
rotate(Garden (Cucumber) = Garden (Cucumber)
rotate(Garden(Lettuce)) = Field(Maize)
rotate(Garden(Tonato)) = Garden(Carret)
rotate(arden(z)) = Vacant
rotate(Field(Wheat)) = Garden (Tomato)
rotate(Field(Naize)) = Garden(Lettuce)
rotate(Field(y)) = Garden(2ucchini)
rotate(z) =z;
val rotate = fm : plot -> plot
= rotate (Field (Oat));
val it = Garden Zucchini : plot
~ rotate (it);
val it = Vacant : plot
= rotate(it);
val it = Field wheat : plot
= rotate(Grove(Fir));
val it = Grove Fir : plot
Notice that wildcard variables can appear anywhere in the parameter. This
is why this is called pattern-matching—Garden(x) and Field(y) are separate
patterns. The value Garden Tomato), for example, actually fits two patterns,
the Garden(Toaato) and Garden(x). When the function is applied, the first
‘matching pattern for the actual parameter is the one that is executed. Ifa more
specific pattern follows a more general pattern, then the more specific pattem
is unreachable, and ML will give an error.
~ fun badFunction(s) = 5
= | badFunction(Garden(Zucchini)) = 10;
stdIn:82.5-89.99 Error: match redundant
> Garden Zucchini =)
Functions can return values of any type, even tuple types. The following
function takes a real and returns its floor and ceiling,
45CHAPTER 1. SET
~ fun floorsndCesling’x) = (#loor(x), ceil (xd);
val flocréndCeiing = fn : real -> int + int
~ floorAndCeiting( 12.8);
val it = (42,13) + int # ane
We can make functions for strings, too, by using some of the string operations
already available. Suppose we want a function that does the opposite of finding
‘a substring—that is, returning the parts of the string that are not the substring
as a tuple.
~ fun antisubstr(s, n, a) =
= (substring(s, 0, n), substring(s, nm, size(s) - m~ n));
val antleubstr = fn: string * int * int -> atring + etring
= antisubstr("aaabbbece", 3, 3);
val it = (Yaaa","ccc") : string * string
Fora more complicated example, we will write a function that takes a string
and capitalizes the first character (assumed to be a letter). We need two new
pieces: The function Char .toUpper that converts a char to an uppercase letter
(if itis lowercase), and the function st that converts a char to a length-one
string:
= fun capitalize(s) =
str(Char.toUpper(String.sub(s, 0))) >
substring(s, 1, size(s)-1);
val capitalize = fn : string -> string
~ capitalize("franklin") ;
val it = "Franklin" ; string
Next, we define a new type along with its operations. You may have noticed
that ML does not have a type corresponding to Q. We can write our own:
~ datatype rational = Fraction of int * int;
datatype rational = Fraction of int + int
461.11. MAKING YOUR OWN OPERATIONS
~ Fraction(3,5);
val it = Fraction (3,5) : rational
Ie might look strange to have a datatype with only one constructor expres-
sion, but do not let that confuse you, ‘The name of the nev type is rational,
and values ofthis type have a paitern with the identifier Fraction as a husk
and a tuple of type int * int as a core. The ints in the tuple correspond to the
numerator and denominator. Here is a function for adding two fractions. It
uses @ function ged for computing the greatest common divisor of two integers,
which we will define in Section 4.10.
~ fun add(Fraction(a, »), Fraction(e, 4)
= Fraction((a + d+ ¢ + b) div gcd(a
- @ *@ div gedaxdeec
d+ctb, bea,
bd, b* a);
val add = fn: rational + rational -> rational
‘The body of the add function is hard to read and inefficient; it computes
the original numerator and denominator three times each and their GCD twice.
We could write this more efficiently (and readably) if we could store our in-
termediate results in variables and reuse them. In ML, this is done using a let
expression, which has the form
Let ; ,; ... ,, in
end
‘The “var declarations” appear exactly as the variable declarations we have
seen earlier. A variable's scope is the range of expressions in which it is valid. A
variable declared in a let expression has scope beginning at its declaration and
ending at the end, including the expressions used to assign values to subsequent
variables declared in the let expression. The value of the entire let expression
is the value of the expression occurring between in and end. Rewriting ada:
= fun add(Fraction(a, b), Fraction(c, 4)) =
Let val munerator'= aed +c bj
val denominator = b # dj
val divisor = ged(numerator, denominator);
in Fraction(numerater div divisor, denominator div divisor)
end
val add = fn : rational + rational -> rational
~ ada (Fraction(1,2), Fraction(1,6));
val it = Fraction (2,3) : rational
a7
let expresionCHAPTER 1. SET
Exercises
aaa
a2
ETE]
aaa
qans
a6
Write 2 function doubie() that takes an int and
multiplies i by 2
Write 2 function divide13by() that takes an int
fand retuens the real result of dividing 13 by that
‘number, unless the parameter is 0, in which case
ie should return “1,
Write a function ad() for the datatype number
defined in Section 1.10. The funetion should take
two numbers and rerurn their sum. If both the
numbers are integers, the result should be an
integer, but if either or both of the parameters
are real, the result should be real. For example,
ada(Ine(5), Inv(12)) should return Int(17),
but add(Iat(S), Real(12.72)) should return
Real (17.72)
Write a funetion dsvsdeh11 that takes ewo ints
and retuins the result of dividing the first by
the second. Specifically, it should return a tu
ple with thee components: The (integer) quo
tient, the (integer) remainder, and the (real) quo
tient. For example, dividea11(43, 4) should re
turn (3,1,3.25). Ifthe divisor is, then it should
return (0, 0, 0.0)
Write a function replacePries() that takes 2
vvalue of the meal datatype from Section 1.10 and
replaces Fries, if that is the side, with Chips. If
Fries is nor the side, then the original me is re.
‘ured unchanged. Pattern-matching can be used
to make this simple.
Write a function replaceChar@ that takes @
string, an int positon im that string and a char and
returns a new string like the original but with t
141.10
position. For example, replaceChar ("rock
#70") should return "rock"
Write a funetion switchSides() that takes a
string and an int and splits the given string
into two substrings at the given position,
switches the two substrings, and returns them
concatenated into a mew string. For exam:
ple, svitehSides("abedefg", 3) should return
“efganca"
aan?
1.11.8 Write a function euteract for the rational wpe
‘which puts the result in simplest form
Write a function multiply for the rational type
which puts the result in simplest form.
Write a function divide for the rational type
‘which puts the result in simplest form,
ie
‘The set of complex numbers is assumed to have a
single infinity, ccc, as opposed to R which has both
2 positive and negative infinity. ‘Thus if a complex
number is represented as n+ mi (where i = v=1),
then limy-.acn + mi = 20, lim-.som-+ mi = ccc,
lim,-ssot + mi = sos, ete. Thus we can design a eom-
plex number type with the following datatype:
datatype complex = Reallng of real + real |
Infinity;
‘This means that a complex number is either the eou-
pling of a real part and an imaginary part (which is a
real number times ) ori is coc
1.11.11 Write a function add for the complex type.
fhe 1-11.12 Write a function euberact for the complex type.
given char replacing what had been in the given 1.11.13 Write a function multiply for the complex type.
1.12
Recursive functions
‘Most interesting functions—and by “interesting” we mean “for which you would
bother to use a computer’—require some sort of repetitive process. The most
natural way to do this in MI
fora function to apply itself to slightly different
data. For example, the factorial of a number, n! is the product of n and all the
natural numbers less than it, with the special case that 0! = 1. So, 1! = 1,
Y= 21,3
= 8-2-1anddl= 4.3.2
1. Now we notice that 4! =4.3!, and
observe that the same pattem is true for the other numbers. Formally,
43112. RECURSIVE FUNCTIONS
if ifn=0
M4 ne(a— 2)! otherwise
In ML,
~ fun factorial (0) = 1
| factorial (n) = n * factorial (n-1);
val factorial
no: int ~> int
~ factorial (0);
val it = 1: ine
~ factorial(2);
val it = 2: int
~ factorial (s);
val it = 120: int
Functions that apply themselves are called recursive, that is, self-referential. recursive
We can use recursion also to take apart strings and process them. In Sec-
tion 1.11 we made a function called capitalize() that converted the first
character in a string to be uppercase. Suppose we want to convert the entire
string to uppercase. If we cared about writing a function only on strings of
length 5, we could write the ridiculous function
~ fun capitalizes (s)
= str (Char. toUpper(String.sub(s, 0)))
str(Char-toUpper(String.eub(s, 1)))
= str(Char.toUpper(String. sub(s, 2)))
= str(Char.toUpper(string.sub(s, 3))) ~
= str(Char.toUpper(string,sub(s, 4));
‘Notation Note: Should we parenthesize parameters?
‘The parentheses around the formal parameter in a function declaration and around the actual parameter in
a function application are unnecessary if there is only one parameter. We could have written
fun factorial 0 = 1
| factorial n= a * factorial tent)
Factorial 3;
In fac, ML. convention is to omit the parentheses. We use them in this book, however, Becnuse it makes
ML look more like mathematical notation.CHAPTER 1. SET
val capitalizes =
fn: string > atring
~ capitalizes("hello");
val ir
neo"
string
‘To write a better function—one that will work on a string of any size, we
need to find a way to break a problem down into a smaller version of itself. We
know that an empty string does not need to be converted—it already has all of
its (nonexistent) characters as uppercase. Ifa string is not empty, then we will
convert the first character, use the function we are writing to convert the rest
of the string, and then concatenate the results.
= fun capitalizeAli(
= | capitalizeéll(s)
str(Char.toUpper (String.sub(s, 0)))
: capitalizeall (substring(s, 1, size(s) ~ 1));
val capitalizeall = fn
string -> string
~ capitalizesll ("discrete math");
val it = "DISCRETE MATH"
string
Writing recursive functions is the most radical concept we have introduced
in this chapter, and it will ake time for you to master. Try the following ex-
cercises, but do not be discouraged if you have trouble. Recursion will be rein-
forced in the next two chapters and throughout this text.
Exercises
1.12.1 Weitea function charCowne that takesa string and
returns the number of characters. In other words,
‘write your own version of eaze for strings—but
do not use size, write your own using patter
matching and recursion. (Hint: The string ** has
O characters, and any other string has one more
character than its substring if you take off the frst
character)
Write a function reverse that takes a string and
reverses it. For example, reverse("hollo'
should return *odten". (Hint: The string "" is
its own reverse. For any other string, remove the
first character, reverse the rest, and tack the frst
character on the back.
1322
50
1.12.3 Notice that che div operator can be used to chop
‘a number up. 1275 div 10 is 127, 127 div 10
Js 32, 12 div 10 4, and 1 div 101s 0. Write
a function digitCount that takes an integer—
assume nonnegative—and returns the number
of digits the number has. (Do not forget that
aigitCount(0) = 1)
1.12.4 Suppose ML did not have a multiplication op-
ferator defined for integers. Write @ function
ultiply that takes two integers and produces
their product. Your function needs to work
only on nonnegative integers. Notice that
sultiply(x, 0) = 0 for any xExercises, continued
1.12.5 Using the same principle as in the previous exer
cise, write a function exp that performs exponen-
tiation on integers; that is, for integers x and n,
‘exp(x, 2) would compute 2"
1.12.6 Write a function that will compute the sum
Dk y i, given u. (There is a fast way to do this,
‘hich does not require repetition. If you know it,
do not use it; do it the “brute force" way.)
A series in the form 3", ar’ Is called a geometric
series. That is, given a value r and a coelficient a,
find the sum of a} ar-+ar? + ar! +... bar"
Write a funetion that computes a geomettic series,
taking n, a, and r as parameters.
112.7
1.12.8 The Fibonacci sequence is defined by repeatedly
adding the two previous numbers in the sequence
(starting with 0 and 1) to obtain the next number,
that is
112.9
1.13. STATEMENTS AND EXCEPTIONS
Write 2 function to compute the nth Fibonacci
‘number, given m
‘A Guesar cipher is an encryption scheme where
ceach letter in the text is shifted up or down the
alphabet. The shift amount is the key. For ex
ample, the word “functional” encrypted with key
3 Is “ixgfwleqdo", since “! comes three letters
after “f°” comes three letters after “u", ete
At the end of the alphabet, we wrap around to
the beginning, so *y” shifted 3 is "b.” Write a
function encodeString that takes a string and a
key and produces the string encrypted with the
given Key (50, encodestring(*funcvional”,
3); should produce "iagfvirglo"). Assume
that the string contains only lower case letters
and spaces, and do not encode spaces. You will
need to write a couple of helper funetions first.
Your function should also work with negative
numbers (any key from —25 to 25); note that
‘oncodeString encodestring(*functional* ,
31, 3), “3) results in "functional
6.1
85,8, 18
1.13) Statements and exceptions
If there is ever a need to display an intermediate result to the screen, this can
be done using the print function, print works only on strings, so values of any
other type would need to be converted to a string,
~ print (*hello");
helloval it = ( : unit
Notice that that since the string "hello" has no end-of-line marker (\n),
the interpreter’s response appears on the same line as the printing of the string.
‘The call of the print function is an example of a statement. A statement is
like an expression except that it does not have a value to return; statements
are executed for their side effect—in this case, printing to the screen. In ML, side offct
statements return a dummy value, (), which is the same as an empty tuple.
‘The unit type is a special type whose only value is ()
We can yoke several expressions together by enclosing them in parenthe-
ses and separating them by semicolons, a construct called a statement list. The staemont ist
interpreter evaluates the expressions in order, discarding their results (thus ef-
fectively making them statements, if they are not already), except for the last
expression, whose result becomes the result of the entire expression. A state-
ment list itself is nor necessarily a statement,
SLCHAPTER 1.
ception
= (B+ 8; 3< 8} real(3) / real (6));
val it = 0.6: reat
‘The only reason one would want to do this is if the earlier expressions were
useful for their side effects—again, such as printing to the screen.
Ivis possible to write a function that does not handle all possible cases for
its parameters, for example, this function to replace tomatoes with another
vegetable in a garden (but leaves gardens of other vegetable unchanged):
= fun replaceTomato(subst, Garden(Tomato)) = Garden(subst)
= | replacoTonato(subst, Garden(x)) = Carden(x) ;
Warning: match nonexhaustive
(subst,Garden Tomato) =>
(subst, Garden x) =>
val replaceTonato = fn : vegetable + plot -> plot
= roplaceTomato(2ucchini, Garden(Tonato));
val it = Garden Zucchini : plot
= replaceTomato(2ucchini, Garden (Carrot));
val it = Garden Carrot : plot
= roplaceTomato(Zucchini, Grove(Maple)) ;
uncaught exception Match [nonexhaustive aatch failure]
Notice that the interpreter gives a warning when we enter the function, in-
dicating that the function as we have written it does not address all possible
input. It works fine on input for which we have defined it, but when we have
something other than a garden as the second parameter, the ML interpreter
raises an exception, a special value indicating some error has occurred. (Per-
haps the term exception is less prejudicial than error—rather than judging what
happened to be wrong, just say it it was “unusual.” This particular exception,
though, was a “match failure.”)
Ifyou anticipate an unusval situation—such as input toa function for which
there is no clear answer—you can define your own variety of exception. This is
very mucit lke declaring a datatype; the exception may have extra information.
~ exception HotAGarden of plot;
521.14, A CUMULATIVE SONG
exception NotAGarden of plot
In this case an exception value indicates the nature of the problem (the
input is not a garden as we expected) and gives the offending value (of type
plot) as extra information. Now we rewrite the function so that it has a case for
this kind of input and, in place of an expression, we raise the exception using
the keyword raise.
~ fun replaceTomato(subst, Garden(Torato)) = Garden(subst)
= | replaceTonato(subst, Garden(x)) = Garden(x)
= | replaceTonato(subst, y) = raise NotAGarden(y) ;
val replaceTonato = fn : vegetable + plot -> plot
~ replaceTonato(Zucchini, Grove(Maple)) ;
uncaught exception NotAGarden
‘The advantage is that the result indicates more specifically what exception
circumstance caused the function's abnormal behavior. Moreover, we can indi-
cate what plan-B action should be taken in the event of an exception by adding
handle clause alter an expression where an exception can come from. If we
think of an exception as something like a datatype, then handle clauses perform
pattern-matching on the exception. In this case, we turn any field of grain into
a lettuce garden and leave everything else (vacant plots and groves) as they
~ roplaceTomato (Cucumber, Fiold(Maize))
= “handle NotAGarden(Field(x)) => Garden(Lettuce)
- | NotaGarden(y) => ys
val it = Garden Lettuce : plot
1.14] Extended example: A cumulative song
Each chapter will end with an extended example, Since we still have met very
litle of the ML programming language, our example here will be simple and
whimsical, yet it will tie together several of the things we have seen in the
chapter
We will write a set of functions to produce the words to the song “The Old
Woman Who Swallowed a Fly.” The structure of the song is interesting be-
cause for each new animal the woman eats, we give a description of eating that
particular animal, and then list the previous animals eaten, and conclude the
woman will die—except for when we hit the spider in the list, which requires
53CHAPTER 1. SET
us to describe the spider every time, and when the woman eats the horse, in
which case the song ends without listing the animals. The reason the woman
eats each animal is dependent on the previous animal eaten—except the fly,
which is the base case.
= datatype animal =
Fly | Spider | Bird | Cat | Dog | Cow | Horse;
datatype aninal =
Bird | Cat | Cow | Dog | Fly | Horse | Spider
~ exception Wil1Dies
exception WilLDie
~ exception DidDie;
exception DidDie
‘The exceptions will be used to determine how to end the particular stanza,
since they do not all end the same way.
= fun animalToString(Fly) = "fly"
| animalToString Spider)
| animalToString Bird)
| animalToString (Cat)
| animalToString og)
1
1
"spider"
aninalToString(Cow)
animal ToString(Horse) =
val animalToString = fn : animal -> string
fun next (Spider) = Fly
| next (Bird) = Spider
next (Cat) = Bird
next (Dog) = Cat
next (Cow) = Dog
next (Horse) = Cow;
Warning: match nonexhaustive
val next = fm ; animal -> animal
= fun reason(x) =
print("She svalloved the " ~ animalToString(x) ~
"te catch the " ~ animalToString(next(x)) ~ "\n");
541.14, A CUMULATIVE SONG
val reagon = fn : animal -> unit
~ fun whyEat(iiorse) = raise Diddie
= | whyBa(Fly) =
(print ("I don’t know vhy she svalloued the fly\n");
raise WillDie) :unit
| whyEat(Spider)
(print ("that wiggled and jiggled and tickled * ~
"aneide her\n") ;
reason(Spider); vhyBat (next (Spider)))
| whyEat(x) = (reason(s); vhyBat (next (x)));
val whyEat = fn : animal -> unit
fun description(Bird) = "How absurd, sho svalloved a bird.\n'
| description(Cat) = "Imagine that, she svalloved a cat.\n
| doscription(Dog) = "What a hog, she swallowed a dog.\n"
| description(Cow) = "I don’t know how she swallowed " ~
"a cov. \n"
| descriptions) =")
val description = fn ; animal -> string
~ fun didzat(x) =
(print ("There was an old lady who swallowed a" ~
- animal ToString(x) * "\n");
- print (description(x)); whyBat(x)) ;
val didEat = fm : animal ~> unit
~ fun stanza(x) =
idEat(x)
handle Willie => print ("I guess she’11 die\n")
= | DidDie => print (“And she died\n") ;
val stanza = in : animal -> unit
~ stanza (Dog);
There vas an old lady who avallowed a dog
What a hog, she svalloved a dog.
She evalloved the dog to catch the cat
She evalloved the cat to catch the bird
She evalloved the bird to catch the epider
55