View difference between Paste ID: pE9cpjwT and epewpmJE
SHOW: | | - or go back to the newest paste.
1
//  
2-
//  Lazy compile-time fizzbuzz, without conditionals or
2+
//  Lazy compile-time fizzbuzz computed by C++ templates,
3-
//  the use of machine arithmetic.
3+
//  without conditionals or the use of machine arithmetic.
4
//
5
//         -- Matt Noonan ([email protected])
6
7
#include <iostream>
8
9
using namespace std;
10
11
//
12
//  The natural numbers: Nat = Zero | Succ Nat
13
//
14
15
template <typename n> 
16
struct Succ 
17
{
18
  typedef Succ eval;
19
  static const unsigned int toInt = 1 + n::toInt;
20
  static void print(ostream & o) { o << toInt; }
21
};
22
23
struct Zero
24
{
25
  typedef Zero eval;
26
  static const unsigned int toInt = 0;
27
  static void print(ostream & o) { o << toInt; }
28
};
29
30
//
31
//  Arithmetic operators
32
//    Plus Zero n = n
33
//    Plus Succ(n) m = Plus n Succ(m)
34
//    Times Zero n = Zero
35
//    Times Succ(n) m = Plus m (Times n m)
36
//
37
38
template <typename a, typename b>
39
struct Plus
40
{
41
  typedef typename Plus<typename a::eval,
42
			typename b::eval>::eval eval;
43
};
44
45
template <typename M> 
46
struct Plus <Zero, M>
47
{ typedef typename M::eval eval; };
48
49
template <typename N, typename M>
50
struct Plus <Succ<N>, M>
51
{ typedef typename Plus<N, Succ<M> >::eval eval; };
52
53
template <typename a, typename b>
54
struct Times
55
{
56
  typedef typename Times<typename a::eval,
57
			 typename b::eval>::eval eval;
58
};
59
60
template <typename M>
61
struct Times <Zero, M>
62
{ typedef Zero::eval eval; };
63
64
template <typename N, typename M>
65
struct Times <Succ<N>, M>
66
{ typedef typename Plus<M,
67
			typename Times<N,M>::eval
68
			>::eval eval; };
69
70
//
71
//  Lists
72
//
73
74
struct Nil
75
{
76
  typedef Nil eval;
77
  static void print(ostream & o) { }
78
};
79
80
template <typename x, typename xs>
81
struct Cons
82
{
83
  typedef Cons eval;
84
  static void print(ostream & o) {
85
    x::eval::print(o); o << endl; xs::eval::print(o);
86
  }
87
};
88
89
//
90
//  Take the first n elements of a list
91
//
92
93
template <typename, typename> struct Take;
94
95
template <typename _> struct Take<Zero,_>
96
{ typedef Nil eval; };
97
98
template <typename n, typename x, typename xs>
99
struct Take<Succ<n>, Cons<x,xs> >
100
{
101
  typedef Cons<x, Take<n, xs> > eval;
102
};
103
104
template <typename a, typename b>
105
struct Take
106
{
107
  typedef typename Take<typename a::eval,
108
			typename b::eval>::eval eval; 
109
};
110
111
//
112
//  Iterate f x0 makes the infinite list
113
//  x0, f(x0), f(f(x0)), ...
114
//
115
116
template <template<typename> class f, typename x0> struct Iterate
117
{
118
  typedef Cons<x0, Iterate<f, f<x0> > > eval; 
119
};
120
121
//
122
//  Map a function over a list
123
//
124
125
template <template<typename> class a, typename b> struct Map
126
{ typedef typename Map<a,
127
		       typename b::eval>::eval eval; 
128
};
129
130
template <template<typename> class f>
131
struct Map<f, Nil>
132
{ typedef Nil eval; };
133
134
template <template<typename> class f, typename x, typename xs>
135
struct Map<f, Cons<x,xs> >
136
{
137
  typedef Cons<f<x>, Map<f,xs> > eval;
138
};
139
140
//
141
//  Some useful things for making fizzes and buzzes
142
//
143
144
struct Fizz
145-
{ static void print(ostream & o) { o << "fizz"; } };
145+
{ static void print(ostream & o) { o << "Fizz"; } };
146
147
struct Buzz
148-
{ static void print(ostream & o) { o << "buzz"; } };
148+
{ static void print(ostream & o) { o << "Buzz"; } };
149
150
struct FizzBuzz
151-
{ static void print(ostream & o) { o << "fizzbuzz"; } };
151+
{ static void print(ostream & o) { o << "FizzBuzz"; } };
152
153
//
154
//  Some useful numbers
155
//
156
157
typedef Succ<Zero> One;
158
typedef Succ<One> Two;
159
typedef Succ<Two> Three;
160
typedef Plus<Two, Three> Five;
161
typedef Times<Two, Five> Ten;
162
typedef Times<Three, Five> Fifteen;
163
typedef Times<Ten, Ten> OneHundred;
164
165
//
166
//  Booleans
167
//
168
169
struct True {};
170
struct False {};
171
172
//
173
//  If/then/else
174
//
175
176
template <typename p, typename t, typename f>
177
struct If
178
{
179
  typedef typename If<typename p::eval, t, f>::eval eval;
180
  static void print(ostream & o) { eval::print(o); }
181
};
182
183
template <typename t, typename _>
184
struct If<True, t, _>
185
{
186
  typedef t eval;
187
};
188
189
template <typename _, typename f>
190
struct If<False, _, f>
191
{ typedef f eval; };
192
	  
193
//
194
//  Testing if x divides y
195
//
196
197
template <typename a, typename b, typename c>
198
struct _Divides
199
{
200
  typedef typename _Divides<typename a::eval,
201
			    typename b::eval,
202
			    typename c::eval>::eval eval;
203
};
204
205
template <typename _, typename __>
206
struct _Divides<_, __, Zero> { typedef False eval; };
207
208
template <typename a>
209
struct _Divides<a, Zero, Zero> { typedef True eval; };
210
211
template <typename a, typename b>
212
struct _Divides<a, Zero, b>
213
{
214
  typedef typename _Divides<a, a, b>::eval eval;
215
};
216
217
template <typename _, typename n, typename m>
218
struct _Divides<_, Succ<n>, Succ<m> >
219
{
220
  typedef typename _Divides<_, n, m>::eval eval;
221
};
222
223
template <typename a, typename b>
224
struct Divides
225
{
226
  typedef typename _Divides<a, a, b>::eval eval;
227
};
228
229
//
230
//  "Otherwise" sugar
231
//
232
233
template <typename a>
234
struct Otherwise
235
{
236
  typedef typename a::eval eval;
237
  static void print(ostream & o) { a::eval::print(o); }
238
};
239
240
//
241
//  Convert a number to fizzes, buzzes as appropriate
242
//
243
244
template <typename n>
245
struct toFizzBuzz
246
{
247
  typedef typename
248
    If< Divides<Fifteen, n>, FizzBuzz,
249
    If< Divides<   Five, n>,     Buzz,
250
    If< Divides<  Three, n>,     Fizz,
251
    Otherwise<                   n
252
    > > > >::eval eval;
253
};
254
255
int main(void) 
256
{
257
  // Make all of the natural numbers
258
  typedef Iterate<Succ, One> Naturals;
259
260
  // Apply fizzbuzz rules to every natural number
261
  typedef Map<toFizzBuzz, Naturals> FizzBuzzedNaturals;
262
263
  // Print out the first hundred fizzbuzzed numbers
264
  Take<OneHundred, FizzBuzzedNaturals>::eval::print(cout);
265
266
  return 0;
267
}