Skip to content

Commit 587640d

Browse files
committed
Replace template<class> with template<typename>
cf. hmemcpy/milewski-ctfp-pdf#309
1 parent d696efc commit 587640d

File tree

18 files changed

+50
-50
lines changed

18 files changed

+50
-50
lines changed

english/part1/ch01.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ There are two extremely important properties that the composition in any categor
111111
When dealing with functions, the identity arrow is implemented as the identity function that just returns back its argument. The implementation is the same for every type, which means this function is universally polymorphic. In C++ we could define it as a template:
112112

113113
```cpp
114-
template<class T> T id(T x) { return x; }
114+
template<typename T> T id(T x) { return x; }
115115
```
116116
117117
\noindent

english/part1/ch02.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ unit _ = ()
194194
In C++ you would write this function as:
195195

196196
```cpp
197-
template<class T>
197+
template<typename T>
198198
void unit(T) {}
199199
```
200200

english/part1/ch03.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,13 @@ The former translates into equality of morphisms in the category $\Hask$ (or $\S
103103
The closest one can get to declaring a monoid in C++ would be to use the C++20 standard's concept feature.
104104

105105
```cpp
106-
template<class T>
106+
template<typename T>
107107
struct mempty;
108108

109-
template<class T>
109+
template<typename T>
110110
T mappend(T, T) = delete;
111111

112-
template<class M>
112+
template<typename M>
113113
concept Monoid = requires (M m) {
114114
{ mempty<M>::value() } -> std::same_as<M>;
115115
{ mappend(m, m); } -> std::same_as<M>;

english/part1/ch04.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ We want to modify the functions `toUpper` and `toWords` so that they piggyback a
103103
We will “embellish” the return values of these functions. Let's do it in a generic way by defining a template `Writer` that encapsulates a pair whose first component is a value of arbitrary type `A` and the second component is a string:
104104

105105
```cpp
106-
template<class A>
106+
template<typename A>
107107
using Writer = pair<A, string>;
108108
```
109109

@@ -185,7 +185,7 @@ So here's the recipe for the composition of two morphisms in this new category w
185185
If we want to abstract this composition as a higher order function in C++, we have to use a template parameterized by three types 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:
186186
187187
```cpp
188-
template<class A, class B, class C>
188+
template<typename A, typename B, typename C>
189189
function<Writer<C>(A)> compose(function<Writer<B>(A)> m1,
190190
function<Writer<C>(B)> m2)
191191
{
@@ -240,7 +240,7 @@ Writer<A> identity(A);
240240
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:
241241

242242
```cpp
243-
template<class A>
243+
template<typename A>
244244
Writer<A> identity(A x) {
245245
return make_pair(x, "");
246246
}
@@ -336,7 +336,7 @@ The particular monad that I used as the basis of the category in this post is ca
336336
A function that is not defined for all possible values of its argument is called a partial function. It's not really a function in the mathematical sense, so it doesn't fit the standard categorical mold. It can, however, be represented by a function that returns an embellished type `optional`:
337337

338338
```cpp
339-
template<class A> class optional {
339+
template<typename A> class optional {
340340
bool _isValid;
341341
A _value;
342342
public:

english/part1/ch05.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ snd (_, y) = y
131131
In C++, we would use template functions, for instance:
132132

133133
```cpp
134-
template<class A, class B>
134+
template<typename A, typename B>
135135
A fst(pair<A, B> const & p) {
136136
return p.first;
137137
}

english/part1/ch06.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ data List a = Nil | Cons a (List a)
272272
can be translated to C++ using the null pointer trick to implement the empty list:
273273

274274
```cpp
275-
template<class A>
275+
template<typename A>
276276
class List {
277277
Node<A> * _head;
278278
public:

english/part1/ch07.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ This is definitely not a valid transformation, and it will not produce the same
194194
Functors are easily expressed in Haskell, but they can be defined in any language that supports generic programming and higher-order functions. Let's consider the C++ analog of `Maybe`, the template type `optional`. Here's a sketch of the implementation (the actual implementation is much more complex, dealing with various ways the argument may be passed, with copy semantics, and with the resource management issues characteristic of C++):
195195

196196
```cpp
197-
template<class T>
197+
template<typename T>
198198
class optional {
199199
bool _isValid; // the tag
200200
T _v;
@@ -210,7 +210,7 @@ public:
210210
This template provides one part of the definition of a functor: the mapping of types. It maps any type `T` to a new type `optional<T>`. Let's define its action on functions:
211211
212212
```cpp
213-
template<class A, class B>
213+
template<typename A, typename B>
214214
std::function<optional<B>(optional<A>)>
215215
fmap(std::function<B(A)> f)
216216
{
@@ -227,7 +227,7 @@ fmap(std::function<B(A)> f)
227227
This is a higher order function, taking a function as an argument and returning a function. Here's the uncurried version of it:
228228

229229
```cpp
230-
template<class A, class B>
230+
template<typename A, typename B>
231231
optional<B> fmap(std::function<B(A)> f, optional<A> opt) {
232232
if (!opt.isValid())
233233
return optional<B>{};
@@ -295,15 +295,15 @@ By the way, the `Functor` class, as well as its instance definitions for a lot o
295295
Can we try the same approach in C++? A type constructor corresponds to a template class, like `optional`, so by analogy, we would parameterize `fmap` with a [*template template parameter*]{.keyword #template_template_parameter}\index{template template parameter} `F`. This is the syntax for it:
296296

297297
```cpp
298-
template<template<class> F, class A, class B>
298+
template<template<typename> F, typename A, typename B>
299299
F<B> fmap(std::function<B(A)>, F<A>);
300300
```
301301
302302
\noindent
303303
We would like to be able to specialize this template for different functors. Unfortunately, there is a prohibition against partial specialization of template functions in C++. You can't write:
304304
305305
```cpp
306-
template<class A, class B>
306+
template<typename A, typename B>
307307
optional<B> fmap<optional>(
308308
std::function<B(A)> f, optional<A> opt)
309309
```
@@ -312,7 +312,7 @@ optional<B> fmap<optional>(
312312
Instead, we have to fall back on function overloading, which brings us back to the original definition of the uncurried `fmap`:
313313

314314
```cpp
315-
template<class A, class B>
315+
template<typename A, typename B>
316316
optional<B> fmap(std::function<B(A)> f, optional<A> opt)
317317
{
318318
if (!opt.isValid())
@@ -360,7 +360,7 @@ instance Functor List where
360360
If you are more comfortable with C++, consider the case of a `std::vector`, which could be considered the most generic C++ container. The implementation of `fmap` for `std::vector` is just a thin encapsulation of `std::transform`:
361361

362362
```cpp
363-
template<class A, class B>
363+
template<typename A, typename B>
364364
std::vector<B> fmap(std::function<B(A)> f, std::vector<A> v)
365365
{
366366
std::vector<B> w;
@@ -468,7 +468,7 @@ instance Functor (Const c) where
468468
This might be a little clearer in C++ (I never thought I would utter those words!), where there is a stronger distinction between type arguments — which are compile-time — and values, which are run-time:
469469

470470
```cpp
471-
template<class C, class A>
471+
template<typename C, typename A>
472472
struct Const {
473473
Const(C v) : _v(v) {}
474474
C _v;
@@ -479,7 +479,7 @@ struct Const {
479479
The C++ implementation of `fmap` also ignores the function argument and essentially re-casts the `Const` argument without changing its value:
480480
481481
```cpp
482-
template<class C, class A, class B>
482+
template<typename C, typename A, typename B>
483483
Const<C, B> fmap(std::function<B(A)> f, Const<C, A> c) {
484484
return Const<C, B>{c._v};
485485
}

english/part1/ch08.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ As I mentioned before, one way of implementing sum types in C++ is through class
218218
The base class must define at least one virtual function in order to support dynamic casting, so we'll make the destructor virtual (which is a good idea in any case):
219219

220220
```cpp
221-
template<class T>
221+
template<typename T>
222222
struct Tree {
223223
virtual ~Tree() {}
224224
};
@@ -228,7 +228,7 @@ struct Tree {
228228
The `Leaf` is just an `Identity` functor in disguise:
229229

230230
```cpp
231-
template<class T>
231+
template<typename T>
232232
struct Leaf : public Tree<T> {
233233
T _label;
234234
Leaf(T l) : _label(l) {}
@@ -239,7 +239,7 @@ struct Leaf : public Tree<T> {
239239
The `Node` is a product type:
240240
241241
```cpp
242-
template<class T>
242+
template<typename T>
243243
struct Node : public Tree<T> {
244244
Tree<T> * _left;
245245
Tree<T> * _right;
@@ -251,7 +251,7 @@ struct Node : public Tree<T> {
251251
When implementing `fmap` we take advantage of dynamic dispatching on the type of the `Tree`. The `Leaf` case applies the `Identity` version of `fmap`, and the `Node` case is treated like a bifunctor composed with two copies of the `Tree` functor. As a C++ programmer, you're probably not used to analyzing code in these terms, but it's a good exercise in categorical thinking.
252252

253253
```cpp
254-
template<class A, class B>
254+
template<typename A, typename B>
255255
Tree<B> * fmap(std::function<B(A)> f, Tree<A> * t)
256256
{
257257
Leaf<A> * pl = dynamic_cast <Leaf<A>*>(t);

english/part1/ch10.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ alpha :: F a -> G a
8282
Keep in mind that it's really a family of functions parameterized by `a`. This is another example of the terseness of the Haskell syntax. A similar construct in C++ would be slightly more verbose:
8383

8484
```cpp
85-
template<class A> G<A> alpha(F<A>);
85+
template<typename A> G<A> alpha(F<A>);
8686
```
8787

8888
\noindent

japanese/part1/ch01.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ f ∷ A → B
113113
関数を扱うとき、恒等射は引数をそのまま返す恒等関数として実装される。この実装はどの型でも同じであり、この関数は普遍的に多相 (universally polymorphic) であることを意味する。これはC++ではテンプレートとして定義できる。
114114

115115
```cpp
116-
template<class T> T id(T x) { return x; }
116+
template<typename T> T id(T x) { return x; }
117117
```
118118
119119
\noindent

0 commit comments

Comments
 (0)