More style tweaks for chapters 1.3 and 1.4

This commit is contained in:
Igal Tabachnik 2017-09-24 09:17:35 +03:00
parent 2662dd8b6e
commit a0bd6ef215
3 changed files with 84 additions and 121 deletions

BIN
ctfp.pdf

Binary file not shown.

View File

@ -90,7 +90,6 @@ Associativity means that:
\begin{verbatim} \begin{verbatim}
(a + b) + c = a + (b + c) (a + b) + c = a + (b + c)
\end{verbatim} \end{verbatim}
(In other words, we can skip parentheses when adding numbers.) (In other words, we can skip parentheses when adding numbers.)
The neutral element is zero, because: The neutral element is zero, because:
@ -98,13 +97,11 @@ The neutral element is zero, because:
\begin{verbatim} \begin{verbatim}
0 + a = a 0 + a = a
\end{verbatim} \end{verbatim}
and and
\begin{verbatim} \begin{verbatim}
a + 0 = a a + 0 = a
\end{verbatim} \end{verbatim}
The second equation is redundant, because addition is commutative \code{(a + b 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. = 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 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 there is a neutral element called \code{mempty} and a binary operation
called \code{mappend}: called \code{mappend}:
\begin{minted}{haskell} \begin{verbatim}
class Monoid m where class Monoid m where
mempty :: m mempty :: m
mappend :: m -> m -> m mappend :: m -> m -> m
\end{minted} \end{verbatim}
The type signature for a two-argument function, The type signature for a two-argument function,
\code{m->m->m}, might look strange at first, \code{m->m->m}, might look strange at first,
but it will make perfect sense after we talk about currying. You may 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 \code{mappend} (this is, in fact, done for you in the standard
Prelude): Prelude):
\begin{minted}{haskell} \begin{verbatim}
instance Monoid String where instance Monoid String where
mempty = "" mempty = ""
mappend = (++) mappend = (++)
\end{minted} \end{verbatim}
Here, we have reused the list concatenation operator \code{(++)}, Here, we have reused the list concatenation operator \code{(++)},
because a \code{String} is just a list of characters. 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 two-argument function by surrounding it with parentheses. Given two
strings, you can concatenate them by inserting \code{++} between them: strings, you can concatenate them by inserting \code{++} between them:
\begin{minted}{haskell} \begin{verbatim}
"Hello " ++ "world!" "Hello " ++ "world!"
\end{minted} \end{verbatim}
or by passing them as two arguments to the parenthesized \code{(++)}: or by passing them as two arguments to the parenthesized \code{(++)}:
\begin{minted}{haskell} \begin{verbatim}
(++) "Hello " "world!" (++) "Hello " "world!"
\end{minted} \end{verbatim}
Notice that arguments to a function are not separated by commas or Notice that arguments to a function are not separated by commas or
surrounded by parentheses. (This is probably the hardest thing to get surrounded by parentheses. (This is probably the hardest thing to get
used to when learning Haskell.) 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 It's worth emphasizing that Haskell lets you express equality of
functions, as in: functions, as in:
\begin{minted}{haskell} \begin{verbatim}
mappend = (++) mappend = (++)
\end{minted} \end{verbatim}
Conceptually, this is different than expressing the equality of values Conceptually, this is different than expressing the equality of values
produced by functions, as in: produced by functions, as in:
\begin{minted}{haskell} \begin{verbatim}
mappend s1 s2 = (++) s1 s2 mappend s1 s2 = (++) s1 s2
\end{minted} \end{verbatim}
The former translates into equality of morphisms in the category The former translates into equality of morphisms in the category
\textbf{Hask} (or \textbf{Set}, if we ignore bottoms, which is the name \textbf{Hask} (or \textbf{Set}, if we ignore bottoms, which is the name
for never-ending calculations). Such equations are not only more 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 The closest one can get to declaring a monoid in C++ would be to use the
(proposed) syntax for concepts. (proposed) syntax for concepts.
\begin{minted}{c++} \begin{verbatim}
template<class T> template<class T>
T mempty = delete; T mempty = delete;
@ -216,9 +207,7 @@ template<class M>
{ mempty<M> } -> M; { mempty<M> } -> M;
{ mappend(m, m); } -> M; { mappend(m, m); } -> M;
}; };
\end{minted} \end{verbatim}
The first definition uses a value template (also proposed). A The first definition uses a value template (also proposed). A
polymorphic value is a family of values --- a different value for every polymorphic value is a family of values --- a different value for every
type. 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 An instantiation of the Monoid concept can be accomplished by providing
appropriate specializations and overloads: appropriate specializations and overloads:
\begin{minted}{c++} \begin{verbatim}
template<> template<>
std::string mempty<std::string> = {""}; std::string mempty<std::string> = {""};
std::string mappend(std::string s1, std::string s2) { std::string mappend(std::string s1, std::string s2) {
return s1 + s2; return s1 + s2;
} }
\end{minted} \end{verbatim}
\section{Monoid as Category}\label{monoid-as-category} \section{Monoid as Category}\label{monoid-as-category}
@ -287,8 +276,8 @@ morphisms that follow appropriate rules of composition.
\begin{figure} \begin{figure}
\centering \centering
\fbox{\includegraphics[width=2.45833in]{images/monoid.jpg}} \fbox{\includegraphics[width=2.45833in]{images/monoid.jpg}}
\end{figure} \end{figure}
String concatenation is an interesting case, because we have a choice of 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. monoid. For all intents and purposes they are one and the same.
\begin{figure} \begin{figure}
\centering \centering
\includegraphics[width=3.12500in]{images/monoidhomset.jpg} \includegraphics[width=3.12500in]{images/monoidhomset.jpg}
\captionsetup{labelformat=empty,font=scriptsize} \captionsetup{labelformat=empty,font=scriptsize}
\caption{Monoid hom-set seen as morphisms and as points in a set.} \caption{Monoid hom-set seen as morphisms and as points in a set.}
\end{figure} \end{figure}
There is just one little nit for mathematicians to pick: morphisms don't 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} \section{Challenges}\label{challenges}
\begin{enumerate} \begin{enumerate}
\tightlist
\item \item
Generate a free category from: Generate a free category from:

View File

@ -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 imperative language, would likely be implemented by mutating some global
state, as in: state, as in:
\begin{minted}{c++} \begin{verbatim}
string logger; string logger;
bool negate(bool b) { bool negate(bool b) {
logger += "Not so! "; logger += "Not so! ";
return !b; return !b;
} }
\end{minted} \end{verbatim}
You know that this is not a pure function, because its memoized version 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}. 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 string argument, and pairing regular output with a string that contains
the updated log: the updated log:
\begin{minted}{c++} \begin{verbatim}
pair<bool, string> negate(bool b, string logger) { pair<bool, string> negate(bool b, string logger) {
return make_pair(!b, logger + "Not so! "); 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 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 every time it's called with the same arguments, and it can be memoized
if necessary. However, considering the cumulative nature of the log, if necessary. However, considering the cumulative nature of the log,
you'd have to memoize all possible histories that can lead to a given you'd have to memoize all possible histories that can lead to a given
call. There would be a separate memo entry for: call. There would be a separate memo entry for:
\begin{minted}{c++} \begin{verbatim}
negate(true, "It was the best of times. "); negate(true, "It was the best of times. ");
\end{minted} \end{verbatim}
and and
\begin{minted}{c++} \begin{verbatim}
negate(true, "It was the worst of times. "); negate(true, "It was the worst of times. ");
\end{minted} \end{verbatim}
and so on. and so on.
It's also not a very good interface for a library function. The callers 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 produce a string, but we'd like to unburden it from producing a log. So
here's the compromise solution: here's the compromise solution:
\begin{minted}{c++} \begin{verbatim}
pair<bool, string> negate(bool b) { pair<bool, string> negate(bool b) {
return make_pair(!b, "Not so! "); return make_pair(!b, "Not so! ");
} }
\end{minted} \end{verbatim}
The idea is that the log will be aggregated \emph{between} function The idea is that the log will be aggregated \emph{between} function
calls. 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 example. We have one function from string to string that turns lower
case characters to upper case: case characters to upper case:
\begin{minted}{c++} \begin{verbatim}
string toUpper(string s) { string toUpper(string s) {
string result; string result;
int (*toupperp)(int) = &toupper; // toupper is overloaded int (*toupperp)(int) = &toupper; // toupper is overloaded
transform(begin(s), end(s), back_inserter(result), toupperp); transform(begin(s), end(s), back_inserter(result), toupperp);
return result; return result;
} }
\end{minted} \end{verbatim}
and another that splits a string into a vector of strings, breaking it and another that splits a string into a vector of strings, breaking it
on whitespace boundaries: on whitespace boundaries:
\begin{minted}{c++} \begin{verbatim}
vector<string> toWords(string s) { vector<string> toWords(string s) {
return words(s); return words(s);
} }
\end{minted} \end{verbatim}
The actual work is done in the auxiliary function \code{words}: The actual work is done in the auxiliary function \code{words}:
\begin{minted}{c++} \begin{verbatim}
vector<string> words(string s) { vector<string> words(string s) {
vector<string> result{""}; vector<string> result{""};
for (auto i = begin(s); i != end(s); ++i) for (auto i = begin(s); i != end(s); ++i)
@ -109,11 +102,11 @@ vector<string> words(string s) {
} }
return result; return result;
} }
\end{minted} \end{verbatim}
\begin{wrapfigure}{R}{0pt} \begin{wrapfigure}[11]{R}{0pt}
\raisebox{0pt}[\dimexpr\height-0.75\baselineskip\relax]{ \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} \end{wrapfigure}
We want to modify the functions \code{toUpper} and \code{toWords} so 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 encapsulates a pair whose first component is a value of arbitrary type
\code{A} and the second component is a string: \code{A} and the second component is a string:
\begin{minted}{c++} \begin{verbatim}
template<class A> template<class A>
using Writer = pair<A, string>; using Writer = pair<A, string>;
\end{minted} \end{verbatim}
Here are the embellished functions: Here are the embellished functions:
\begin{minted}{c++} \begin{verbatim}
Writer<string> toUpper(string s) { Writer<string> toUpper(string s) {
string result; string result;
int (*toupperp)(int) = &toupper; int (*toupperp)(int) = &toupper;
@ -143,20 +135,18 @@ Writer<string> toUpper(string s) {
Writer<vector<string>> toWords(string s) { Writer<vector<string>> toWords(string s) {
return make_pair(words(s), "toWords "); return make_pair(words(s), "toWords ");
} }
\end{minted} \end{verbatim}
We want to compose these two functions into another embellished function We want to compose these two functions into another embellished function
that uppercases a string and splits it into words, all the while 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: producing a log of those actions. Here's how we may do it:
\begin{minted}{c++} \begin{verbatim}
Writer<vector<string>> process(string s) { Writer<vector<string>> process(string s) {
auto p1 = toUpper(s); auto p1 = toUpper(s);
auto p2 = toWords(p1.first); auto p2 = toWords(p1.first);
return make_pair(p2.first, p1.second + p2.second); 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 We have accomplished our goal: The aggregation of the log is no longer
the concern of the individual functions. They produce their own the concern of the individual functions. They produce their own
messages, which are then, externally, concatenated into a larger log. 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 between the objects \code{int} and \code{bool}, even though the
embellished function returns a pair: embellished function returns a pair:
\begin{minted}{c++} \begin{verbatim}
pair<bool, string> isEven(int n) { pair<bool, string> isEven(int n) {
return make_pair(n % 2 == 0, "isEven "); 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 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 with another morphism that goes from the object \code{bool} to
whatever. In particular, we should be able to compose it with our whatever. In particular, we should be able to compose it with our
earlier \code{negate}: earlier \code{negate}:
\begin{minted}{c++} \begin{verbatim}
pair<bool, string> negate(bool b) { pair<bool, string> negate(bool b) {
return make_pair(!b, "Not so! "); return make_pair(!b, "Not so! ");
} }
\end{minted} \end{verbatim}
Obviously, we cannot compose these two morphisms the same way we compose Obviously, we cannot compose these two morphisms the same way we compose
regular functions, because of the input/output mismatch. Their regular functions, because of the input/output mismatch. Their
composition should look more like this: composition should look more like this:
\begin{minted}{c++} \begin{verbatim}
pair<bool, string> isOdd(int n) { pair<bool, string> isOdd(int n) {
pair<bool, string> p1 = isEven(n); pair<bool, string> p1 = isEven(n);
pair<bool, string> p2 = negate(p1.first); pair<bool, string> p2 = negate(p1.first);
return make_pair(p2.first, p1.second + p2.second); 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 So here's the recipe for the composition of two morphisms in this new
category we are constructing: 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 embellished functions that are composable according to our rules, and
return a third embellished function: return a third embellished function:
\begin{minted}{c++} \begin{verbatim}
template<class A, class B, class C> template<class A, class B, class C>
function<Writer<C>(A)> compose(function<Writer<B>(A)> m1, function<Writer<C>(A)> compose(function<Writer<B>(A)> m1,
function<Writer<C>(B)> m2) 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); 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 Now we can go back to our earlier example and implement the composition
of \code{toUpper} and \code{toWords} using this new template: of \code{toUpper} and \code{toWords} using this new template:
\begin{minted}{c++} \begin{minted}[breaklines, breakafter=>>]{text}
Writer<vector<string>> process(string s) { Writer<vector<string>> process(string s) {
return compose<string, string, vector<string>>(toUpper, toWords)(s); return compose<string, string, vector<string>>(toUpper, toWords)(s);
} }
\end{minted} \end{minted}
There is still a lot of noise with the passing of types to the 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 \code{compose} template. This can be avoided as long as you have a
C++14-compliant compiler that supports generalized lambda functions with C++14-compliant compiler that supports generalized lambda functions with
return type deduction (credit for this code goes to Eric Niebler): return type deduction (credit for this code goes to Eric Niebler):
\begin{minted}{c++} \begin{verbatim}
auto const compose = [](auto m1, auto m2) { auto const compose = [](auto m1, auto m2) {
return [m1, m2](auto x) { return [m1, m2](auto x) {
auto p1 = m1(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); return make_pair(p2.first, p1.second + p2.second);
}; };
}; };
\end{minted} \end{verbatim}
In this new definition, the implementation of \code{process} In this new definition, the implementation of \code{process}
simplifies to: simplifies to:
\begin{minted}{c++} \begin{verbatim}
Writer<vector<string>> process(string s) { Writer<vector<string>> process(string s) {
return compose(toUpper, toWords)(s); return compose(toUpper, toWords)(s);
} }
\end{minted} \end{verbatim}
But we are not finished yet. We have defined composition in our new 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 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 identity functions! They have to be morphisms from type A back to type
A, which means they are embellished functions of the form: A, which means they are embellished functions of the form:
\begin{minted}{c++} \begin{verbatim}
Writer<A> identity(A); Writer<A> identity(A);
\end{minted} \end{verbatim}
They have to behave like units with respect to composition. If you look 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 at our definition of composition, you'll see that an identity morphism
should pass its argument without change, and only contribute an empty should pass its argument without change, and only contribute an empty
string to the log: string to the log:
\begin{minted}{c++} \begin{verbatim}
template<class A> Writer<A> identity(A x) { template<class A> Writer<A> identity(A x) {
return make_pair(x, ""); return make_pair(x, "");
} }
\end{minted} \end{verbatim}
You can easily convince yourself that the category we have just defined You can easily convince yourself that the category we have just defined
is indeed a legitimate category. In particular, our composition is is indeed a legitimate category. In particular, our composition is
trivially associative. If you follow what's happening with the first 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} more help from the compiler. Let's start by defining the \code{Writer}
type: type:
\begin{minted}{haskell} \begin{verbatim}
type Writer a = (a, String) type Writer a = (a, String)
\end{minted} \end{verbatim}
Here I'm just defining a type alias, an equivalent of a \code{typedef} 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 (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 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 Our morphisms are functions from an arbitrary type to some
\code{Writer} type: \code{Writer} type:
\begin{minted}{haskell} \begin{verbatim}
a -> Writer b a -> Writer b
\end{minted} \end{verbatim}
We'll declare the composition as a funny infix operator, sometimes We'll declare the composition as a funny infix operator, sometimes
called the ``fish'': called the ``fish'':
\begin{minted}{haskell} \begin{verbatim}
(>=>) :: (a -> Writer b) -> (b -> Writer c) -> (a -> Writer c) (>=>) :: (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 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 returning a function. The first argument is of the type
\code{(a->Writer b)}, the second is \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 \code{m1} and \code{m2} appearing on either side of the fishy
symbol: symbol:
\begin{minted}{haskell} \begin{verbatim}
m1 >=> m2 = \x -> m1 >=> m2 = \x ->
let (y, s1) = m1 x let (y, s1) = m1 x
(z, s2) = m2 y (z, s2) = m2 y
in (z, s1 ++ s2) in (z, s1 ++ s2)
\end{minted} \end{verbatim}
The result is a lambda function of one argument \code{x}. The lambda 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 is written as a backslash --- think of it as the Greek letter λ with an
amputated leg. 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 reasons that will become clear much later, I will call it
\code{return}. \code{return}.
\begin{minted}{haskell} \begin{verbatim}
return :: a -> Writer a return :: a -> Writer a
return x = (x, "") return x = (x, "")
\end{minted} \end{verbatim}
For completeness, let's have the Haskell versions of the embellished For completeness, let's have the Haskell versions of the embellished
functions \code{upCase} and \code{toWords}: functions \code{upCase} and \code{toWords}:
\begin{minted}{haskell} \begin{verbatim}
upCase :: String -> Writer String upCase :: String -> Writer String
upCase s = (map toUpper s, "upCase ") upCase s = (map toUpper s, "upCase ")
\end{minted} \end{verbatim}
\begin{minted}{haskell} \begin{verbatim}
toWords :: String -> Writer [String] toWords :: String -> Writer [String]
toWords s = (words s, "toWords ") toWords s = (words s, "toWords ")
\end{minted} \end{verbatim}
The function \code{map} corresponds to the C++ \code{transform}. It The function \code{map} corresponds to the C++ \code{transform}. It
applies the character function \code{toUpper} to the string applies the character function \code{toUpper} to the string
\code{s}. The auxiliary function \code{words} is defined in the \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 Finally, the composition of the two functions is accomplished with the
help of the fish operator: help of the fish operator:
\begin{minted}{haskell} \begin{verbatim}
process :: String -> Writer [String] process :: String -> Writer [String]
process = upCase >=> toWords process = upCase >=> toWords
\end{minted} \end{verbatim}
\section{Kleisli Categories}\label{kleisli-categories} \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 can, however, be represented by a function that returns an embellished
type \code{optional}: type \code{optional}:
\begin{minted}{c++} \begin{verbatim}
template<class A> class optional { template<class A> class optional {
bool _isValid; bool _isValid;
A _value; A _value;
@ -467,18 +442,16 @@ public:
bool isValid() const { return _isValid; } bool isValid() const { return _isValid; }
A value() const { return _value; } A value() const { return _value; }
}; };
\end{minted} \end{verbatim}
As an example, here's the implementation of the embellished function As an example, here's the implementation of the embellished function
\code{safe\_root}: \code{safe\_root}:
\begin{minted}{c++} \begin{verbatim}
optional<double> safe_root(double x) { optional<double> safe_root(double x) {
if (x >= 0) return optional<double>{sqrt(x)}; if (x >= 0) return optional<double>{sqrt(x)};
else return optional<double>{}; else return optional<double>{};
} }
\end{minted} \end{verbatim}
Here's the challenge: Here's the challenge:
\begin{enumerate} \begin{enumerate}