mirror of
https://github.com/hmemcpy/milewski-ctfp-pdf.git
synced 2024-11-22 20:01:25 +03:00
More style tweaks for chapters 1.3 and 1.4
This commit is contained in:
parent
2662dd8b6e
commit
a0bd6ef215
@ -90,7 +90,6 @@ Associativity means that:
|
||||
\begin{verbatim}
|
||||
(a + b) + c = a + (b + c)
|
||||
\end{verbatim}
|
||||
|
||||
(In other words, we can skip parentheses when adding numbers.)
|
||||
|
||||
The neutral element is zero, because:
|
||||
@ -98,13 +97,11 @@ The neutral element is zero, because:
|
||||
\begin{verbatim}
|
||||
0 + a = a
|
||||
\end{verbatim}
|
||||
|
||||
and
|
||||
|
||||
\begin{verbatim}
|
||||
a + 0 = a
|
||||
\end{verbatim}
|
||||
|
||||
The second equation is redundant, because addition is commutative \code{(a + b
|
||||
= b + a)}, but commutativity is not part of the definition of a monoid.
|
||||
For instance, string concatenation is not commutative and yet it forms a
|
||||
@ -116,12 +113,11 @@ In Haskell we can define a type class for monoids --- a type for which
|
||||
there is a neutral element called \code{mempty} and a binary operation
|
||||
called \code{mappend}:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
class Monoid m where
|
||||
mempty :: m
|
||||
mappend :: m -> m -> m
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
The type signature for a two-argument function,
|
||||
\code{m->m->m}, might look strange at first,
|
||||
but it will make perfect sense after we talk about currying. You may
|
||||
@ -147,12 +143,11 @@ be a monoid by providing the implementation of \code{mempty} and
|
||||
\code{mappend} (this is, in fact, done for you in the standard
|
||||
Prelude):
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
instance Monoid String where
|
||||
mempty = ""
|
||||
mappend = (++)
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Here, we have reused the list concatenation operator \code{(++)},
|
||||
because a \code{String} is just a list of characters.
|
||||
|
||||
@ -160,16 +155,14 @@ A word about Haskell syntax: Any infix operator can be turned into a
|
||||
two-argument function by surrounding it with parentheses. Given two
|
||||
strings, you can concatenate them by inserting \code{++} between them:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
"Hello " ++ "world!"
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
or by passing them as two arguments to the parenthesized \code{(++)}:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
(++) "Hello " "world!"
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Notice that arguments to a function are not separated by commas or
|
||||
surrounded by parentheses. (This is probably the hardest thing to get
|
||||
used to when learning Haskell.)
|
||||
@ -177,17 +170,15 @@ used to when learning Haskell.)
|
||||
It's worth emphasizing that Haskell lets you express equality of
|
||||
functions, as in:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
mappend = (++)
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Conceptually, this is different than expressing the equality of values
|
||||
produced by functions, as in:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
mappend s1 s2 = (++) s1 s2
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
The former translates into equality of morphisms in the category
|
||||
\textbf{Hask} (or \textbf{Set}, if we ignore bottoms, which is the name
|
||||
for never-ending calculations). Such equations are not only more
|
||||
@ -204,7 +195,7 @@ so this might be a little confusing to the beginner.)
|
||||
The closest one can get to declaring a monoid in C++ would be to use the
|
||||
(proposed) syntax for concepts.
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
template<class T>
|
||||
T mempty = delete;
|
||||
|
||||
@ -216,9 +207,7 @@ template<class M>
|
||||
{ mempty<M> } -> M;
|
||||
{ mappend(m, m); } -> M;
|
||||
};
|
||||
\end{minted}
|
||||
|
||||
|
||||
\end{verbatim}
|
||||
The first definition uses a value template (also proposed). A
|
||||
polymorphic value is a family of values --- a different value for every
|
||||
type.
|
||||
@ -234,14 +223,14 @@ type) that tests whether there exist appropriate definitions of
|
||||
An instantiation of the Monoid concept can be accomplished by providing
|
||||
appropriate specializations and overloads:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
template<>
|
||||
std::string mempty<std::string> = {""};
|
||||
|
||||
std::string mappend(std::string s1, std::string s2) {
|
||||
return s1 + s2;
|
||||
}
|
||||
\end{minted}
|
||||
\end{verbatim}
|
||||
|
||||
\section{Monoid as Category}\label{monoid-as-category}
|
||||
|
||||
@ -287,8 +276,8 @@ morphisms that follow appropriate rules of composition.
|
||||
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\fbox{\includegraphics[width=2.45833in]{images/monoid.jpg}}
|
||||
\centering
|
||||
\fbox{\includegraphics[width=2.45833in]{images/monoid.jpg}}
|
||||
\end{figure}
|
||||
|
||||
String concatenation is an interesting case, because we have a choice of
|
||||
@ -315,10 +304,10 @@ this product. So we can always recover a set monoid from a category
|
||||
monoid. For all intents and purposes they are one and the same.
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=3.12500in]{images/monoidhomset.jpg}
|
||||
\captionsetup{labelformat=empty,font=scriptsize}
|
||||
\caption{Monoid hom-set seen as morphisms and as points in a set.}
|
||||
\centering
|
||||
\includegraphics[width=3.12500in]{images/monoidhomset.jpg}
|
||||
\captionsetup{labelformat=empty,font=scriptsize}
|
||||
\caption{Monoid hom-set seen as morphisms and as points in a set.}
|
||||
\end{figure}
|
||||
|
||||
There is just one little nit for mathematicians to pick: morphisms don't
|
||||
@ -341,6 +330,7 @@ according to his and Bjarne Stroustrup's latest proposal.
|
||||
\section{Challenges}\label{challenges}
|
||||
|
||||
\begin{enumerate}
|
||||
\tightlist
|
||||
\item
|
||||
Generate a free category from:
|
||||
|
||||
|
@ -5,15 +5,14 @@ functions that log or trace their execution. Something that, in an
|
||||
imperative language, would likely be implemented by mutating some global
|
||||
state, as in:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
string logger;
|
||||
|
||||
bool negate(bool b) {
|
||||
logger += "Not so! ";
|
||||
return !b;
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
You know that this is not a pure function, because its memoized version
|
||||
would fail to produce a log. This function has \newterm{side effects}.
|
||||
|
||||
@ -26,28 +25,25 @@ have to pass the log explicitly, in and out. Let's do that by adding a
|
||||
string argument, and pairing regular output with a string that contains
|
||||
the updated log:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
pair<bool, string> negate(bool b, string logger) {
|
||||
return make_pair(!b, logger + "Not so! ");
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
This function is pure, it has no side effects, it returns the same pair
|
||||
every time it's called with the same arguments, and it can be memoized
|
||||
if necessary. However, considering the cumulative nature of the log,
|
||||
you'd have to memoize all possible histories that can lead to a given
|
||||
call. There would be a separate memo entry for:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
negate(true, "It was the best of times. ");
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
and
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
negate(true, "It was the worst of times. ");
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
and so on.
|
||||
|
||||
It's also not a very good interface for a library function. The callers
|
||||
@ -64,12 +60,11 @@ continuous log is a separate concern. We still want the function to
|
||||
produce a string, but we'd like to unburden it from producing a log. So
|
||||
here's the compromise solution:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
pair<bool, string> negate(bool b) {
|
||||
return make_pair(!b, "Not so! ");
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
The idea is that the log will be aggregated \emph{between} function
|
||||
calls.
|
||||
|
||||
@ -77,27 +72,25 @@ To see how this can be done, let's switch to a slightly more realistic
|
||||
example. We have one function from string to string that turns lower
|
||||
case characters to upper case:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
string toUpper(string s) {
|
||||
string result;
|
||||
int (*toupperp)(int) = &toupper; // toupper is overloaded
|
||||
transform(begin(s), end(s), back_inserter(result), toupperp);
|
||||
return result;
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
and another that splits a string into a vector of strings, breaking it
|
||||
on whitespace boundaries:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
vector<string> toWords(string s) {
|
||||
return words(s);
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
The actual work is done in the auxiliary function \code{words}:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
vector<string> words(string s) {
|
||||
vector<string> result{""};
|
||||
for (auto i = begin(s); i != end(s); ++i)
|
||||
@ -109,11 +102,11 @@ vector<string> words(string s) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
\end{minted}
|
||||
\end{verbatim}
|
||||
|
||||
\begin{wrapfigure}{R}{0pt}
|
||||
\begin{wrapfigure}[11]{R}{0pt}
|
||||
\raisebox{0pt}[\dimexpr\height-0.75\baselineskip\relax]{
|
||||
\fbox{\includegraphics[width=1.83333in]{images/piggyback.jpg}}}%
|
||||
\fbox{\includegraphics[width=1.83333in]{images/piggyback.jpg}}}%
|
||||
\end{wrapfigure}
|
||||
|
||||
We want to modify the functions \code{toUpper} and \code{toWords} so
|
||||
@ -125,14 +118,13 @@ in a generic way by defining a template \code{Writer} that
|
||||
encapsulates a pair whose first component is a value of arbitrary type
|
||||
\code{A} and the second component is a string:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
template<class A>
|
||||
using Writer = pair<A, string>;
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Here are the embellished functions:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
Writer<string> toUpper(string s) {
|
||||
string result;
|
||||
int (*toupperp)(int) = &toupper;
|
||||
@ -143,20 +135,18 @@ Writer<string> toUpper(string s) {
|
||||
Writer<vector<string>> toWords(string s) {
|
||||
return make_pair(words(s), "toWords ");
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
We want to compose these two functions into another embellished function
|
||||
that uppercases a string and splits it into words, all the while
|
||||
producing a log of those actions. Here's how we may do it:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
Writer<vector<string>> process(string s) {
|
||||
auto p1 = toUpper(s);
|
||||
auto p2 = toWords(p1.first);
|
||||
return make_pair(p2.first, p1.second + p2.second);
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
We have accomplished our goal: The aggregation of the log is no longer
|
||||
the concern of the individual functions. They produce their own
|
||||
messages, which are then, externally, concatenated into a larger log.
|
||||
@ -184,35 +174,32 @@ important point is that this morphism is still considered an arrow
|
||||
between the objects \code{int} and \code{bool}, even though the
|
||||
embellished function returns a pair:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
pair<bool, string> isEven(int n) {
|
||||
return make_pair(n % 2 == 0, "isEven ");
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
By the laws of a category, we should be able to compose this morphism
|
||||
with another morphism that goes from the object \code{bool} to
|
||||
whatever. In particular, we should be able to compose it with our
|
||||
earlier \code{negate}:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
pair<bool, string> negate(bool b) {
|
||||
return make_pair(!b, "Not so! ");
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Obviously, we cannot compose these two morphisms the same way we compose
|
||||
regular functions, because of the input/output mismatch. Their
|
||||
composition should look more like this:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
pair<bool, string> isOdd(int n) {
|
||||
pair<bool, string> p1 = isEven(n);
|
||||
pair<bool, string> p2 = negate(p1.first);
|
||||
return make_pair(p2.first, p1.second + p2.second);
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
So here's the recipe for the composition of two morphisms in this new
|
||||
category we are constructing:
|
||||
|
||||
@ -237,7 +224,7 @@ corresponding to three objects in our category. It should take two
|
||||
embellished functions that are composable according to our rules, and
|
||||
return a third embellished function:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
template<class A, class B, class C>
|
||||
function<Writer<C>(A)> compose(function<Writer<B>(A)> m1,
|
||||
function<Writer<C>(B)> m2)
|
||||
@ -248,23 +235,21 @@ function<Writer<C>(A)> compose(function<Writer<B>(A)> m1,
|
||||
return make_pair(p2.first, p1.second + p2.second);
|
||||
};
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Now we can go back to our earlier example and implement the composition
|
||||
of \code{toUpper} and \code{toWords} using this new template:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{minted}[breaklines, breakafter=>>]{text}
|
||||
Writer<vector<string>> process(string s) {
|
||||
return compose<string, string, vector<string>>(toUpper, toWords)(s);
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
There is still a lot of noise with the passing of types to the
|
||||
\code{compose} template. This can be avoided as long as you have a
|
||||
C++14-compliant compiler that supports generalized lambda functions with
|
||||
return type deduction (credit for this code goes to Eric Niebler):
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
auto const compose = [](auto m1, auto m2) {
|
||||
return [m1, m2](auto x) {
|
||||
auto p1 = m1(x);
|
||||
@ -272,37 +257,33 @@ auto const compose = [](auto m1, auto m2) {
|
||||
return make_pair(p2.first, p1.second + p2.second);
|
||||
};
|
||||
};
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
In this new definition, the implementation of \code{process}
|
||||
simplifies to:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
Writer<vector<string>> process(string s) {
|
||||
return compose(toUpper, toWords)(s);
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
But we are not finished yet. We have defined composition in our new
|
||||
category, but what are the identity morphisms? These are not our regular
|
||||
identity functions! They have to be morphisms from type A back to type
|
||||
A, which means they are embellished functions of the form:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
Writer<A> identity(A);
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
They have to behave like units with respect to composition. If you look
|
||||
at our definition of composition, you'll see that an identity morphism
|
||||
should pass its argument without change, and only contribute an empty
|
||||
string to the log:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
template<class A> Writer<A> identity(A x) {
|
||||
return make_pair(x, "");
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
You can easily convince yourself that the category we have just defined
|
||||
is indeed a legitimate category. In particular, our composition is
|
||||
trivially associative. If you follow what's happening with the first
|
||||
@ -325,10 +306,9 @@ The same thing in Haskell is a little more terse, and we also get a lot
|
||||
more help from the compiler. Let's start by defining the \code{Writer}
|
||||
type:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
type Writer a = (a, String)
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Here I'm just defining a type alias, an equivalent of a \code{typedef}
|
||||
(or \code{using}) in C++. The type \code{Writer} is parameterized by
|
||||
a type variable \code{a} and is equivalent to a pair of \code{a} and
|
||||
@ -338,17 +318,15 @@ parentheses, separated by a comma.
|
||||
Our morphisms are functions from an arbitrary type to some
|
||||
\code{Writer} type:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
a -> Writer b
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
We'll declare the composition as a funny infix operator, sometimes
|
||||
called the ``fish'':
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
(>=>) :: (a -> Writer b) -> (b -> Writer c) -> (a -> Writer c)
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
It's a function of two arguments, each being a function on its own, and
|
||||
returning a function. The first argument is of the type
|
||||
\code{(a->Writer b)}, the second is
|
||||
@ -359,13 +337,12 @@ Here's the definition of this infix operator --- the two arguments
|
||||
\code{m1} and \code{m2} appearing on either side of the fishy
|
||||
symbol:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
m1 >=> m2 = \x ->
|
||||
let (y, s1) = m1 x
|
||||
(z, s2) = m2 y
|
||||
in (z, s1 ++ s2)
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
The result is a lambda function of one argument \code{x}. The lambda
|
||||
is written as a backslash --- think of it as the Greek letter λ with an
|
||||
amputated leg.
|
||||
@ -389,24 +366,22 @@ I will also define the identity morphism for our category, but for
|
||||
reasons that will become clear much later, I will call it
|
||||
\code{return}.
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
return :: a -> Writer a
|
||||
return x = (x, "")
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
For completeness, let's have the Haskell versions of the embellished
|
||||
functions \code{upCase} and \code{toWords}:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
upCase :: String -> Writer String
|
||||
upCase s = (map toUpper s, "upCase ")
|
||||
\end{minted}
|
||||
\end{verbatim}
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
toWords :: String -> Writer [String]
|
||||
toWords s = (words s, "toWords ")
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
The function \code{map} corresponds to the C++ \code{transform}. It
|
||||
applies the character function \code{toUpper} to the string
|
||||
\code{s}. The auxiliary function \code{words} is defined in the
|
||||
@ -415,10 +390,10 @@ standard Prelude library.
|
||||
Finally, the composition of the two functions is accomplished with the
|
||||
help of the fish operator:
|
||||
|
||||
\begin{minted}{haskell}
|
||||
\begin{verbatim}
|
||||
process :: String -> Writer [String]
|
||||
process = upCase >=> toWords
|
||||
\end{minted}
|
||||
\end{verbatim}
|
||||
|
||||
\section{Kleisli Categories}\label{kleisli-categories}
|
||||
|
||||
@ -457,7 +432,7 @@ mathematical sense, so it doesn't fit the standard categorical mold. It
|
||||
can, however, be represented by a function that returns an embellished
|
||||
type \code{optional}:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
template<class A> class optional {
|
||||
bool _isValid;
|
||||
A _value;
|
||||
@ -467,18 +442,16 @@ public:
|
||||
bool isValid() const { return _isValid; }
|
||||
A value() const { return _value; }
|
||||
};
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
As an example, here's the implementation of the embellished function
|
||||
\code{safe\_root}:
|
||||
|
||||
\begin{minted}{c++}
|
||||
\begin{verbatim}
|
||||
optional<double> safe_root(double x) {
|
||||
if (x >= 0) return optional<double>{sqrt(x)};
|
||||
else return optional<double>{};
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\end{verbatim}
|
||||
Here's the challenge:
|
||||
|
||||
\begin{enumerate}
|
||||
|
Loading…
Reference in New Issue
Block a user