1
- LIBF 0.2 -- Reinventing C++ as a Pure Functional Programming Language
2
- =====================================================================
1
+ LIBF++ 0.2 -- C++ as a Pure Functional Language
2
+ ===============================================
3
3
4
- Libf is a library that supports pure functional programming in C++.
4
+ LibF is a library that supports pure functional programming in C++.
5
5
6
6
Modern C++ purports to be a "multi-paradigm" programming language supporting
7
7
procedural, object-oriented and functional features. In reality however, most
@@ -23,17 +23,17 @@ the above code can be translated into:
23
23
24
24
F::Vector<int> xs;
25
25
for (int i = 0; i < 10; i++)
26
- xs = push_back(xs, i);
26
+ xs = F:: push_back(xs, i);
27
27
28
28
Unlike the standard C++ library, LibF objects are * immutable* . This makes the
29
29
following code possible:
30
30
31
31
F::Vector<int> xs;
32
32
for (int i = 0; i < 5; i++)
33
- xs = push_back(xs, i);
33
+ xs = F:: push_back(xs, i);
34
34
F::Vector<int> ys = xs; // Save the current xs
35
35
for (int i = 0; i < 5; i++)
36
- xs = push_back(xs, i);
36
+ xs = F:: push_back(xs, i);
37
37
printf("%s\n%s\n", c_str(show(ys)), c_str(show(xs)));
38
38
39
39
This code will print:
@@ -45,8 +45,9 @@ The old object `ys` was unaffected by the changes made to its copy `xs`. And
45
45
just like stdlib++, the LibF vector ` push_back ` operation is still O(1) --
46
46
although the constant factors may differ (see below).
47
47
48
- Using C++ as a functional programming language has several advantages.
49
- Namely:
48
+ With immutable objects, it is possible to use (a subset of) C++ as a pure
49
+ functional programming language. Compared to other functional languages, C++
50
+ has several advantages, namely:
50
51
51
52
* * Compiler Support* . C++ is supported by several stable, mature optimizing
52
53
compilers.
@@ -152,10 +153,11 @@ In principle, this can be replaced with:
152
153
153
154
F::Vector<int> xs;
154
155
for (int i = 0; i < 10; i++)
155
- xs = push_back(xs, i);
156
+ xs = F:: push_back(xs, i);
156
157
157
- Although each ` push_back ` operation is still O(1), the constant factors differ
158
- by a factor of 100. Instead it may be better to use a list instead, e.g.:
158
+ Although each ` F::push_back ` operation is still O(1), the constant factors
159
+ differ by a factor of 100. Instead it may be better to use a list instead,
160
+ e.g.:
159
161
160
162
F::List<int> xs;
161
163
for (int i = 0; i < 10; i++)
@@ -175,7 +177,7 @@ create your own list type:
175
177
template <typename T> struct NODE;
176
178
struct EMPTY;
177
179
template <typename T>
178
- using LIST = Union<EMPTY, NODE<T>>;
180
+ using LIST = F:: Union<EMPTY, NODE<T>>;
179
181
struct EMPTY { };
180
182
struct NODE
181
183
{
@@ -190,12 +192,12 @@ The type `LIST` is defined to be a discriminated union between the `EMPTY` and
190
192
can be passed-by-copy. The index of the underlying type for a discriminated
191
193
union is returned by a special ` index ` function. The discriminated union type
192
194
can then be cast to the underlying type, and vice versa. For example, the
193
- following function reverses a ` LIST ` :
195
+ following function reverses a ` LIST ` by accumulating onto ` ys ` :
194
196
195
197
template <typename T>
196
198
PURE LIST<T> reverse(LIST<T> xs, LIST<T> ys)
197
199
{
198
- switch (index(xs)) // Determine if xs is a node or empty.
200
+ switch (F:: index(xs)) // Determine if xs is a node or empty.
199
201
{
200
202
case LIST_EMPTY:
201
203
return ys;
@@ -265,19 +267,21 @@ Unsurprisingly, constructing a `std::vector` is the fastest. The fastest for
265
267
LibF is constructing a linked-list ` F::List ` , followed by ` F::Vector ` .
266
268
Constructing ` F::map ` has about twice the overhead as the mutable ` std::map `
267
269
counterpart. Such results are expected (immutability has inherit costs).
270
+ Note that these benchmarks assume that the garbage collector is disabled.
271
+ Otherwise garbage collector overheads become a significant factor about the 3M
272
+ mark.
268
273
269
- The following compares the time to scan each data structure using a C++ range
270
- loop, i.e.:
274
+ The following compares the time to scan each data structure using ` foldl ` or a
275
+ C++ range loop, i.e.:
271
276
272
277
int sum = 0;
273
278
for (auto x: xs) sum += x;
274
279
275
280
![ Benchmarks2] ( http://comp.nus.edu.sg/~gregory/images/LibF_benchs2.png )
276
281
277
- Note that this uses iterators, which are slower for LibF data structures
278
- compared to the mutable standard library counterparts. An alternative is to
279
- use ` foldl ` when appropriate, which generally faster than iterators, but is
280
- less expressive in general.
282
+ Note that range loops use iterators, which are slower for LibF data structures
283
+ compared to the mutable standard library counterparts. The ` foldl `
284
+ alternatives are faster, but are less expressive in general.
281
285
282
286
Library Documentation:
283
287
----------------------
0 commit comments