1<!-- Copyright 2018 Paul Fultz II
2     Distributed under the Boost Software License, Version 1.0.
3     (http://www.boost.org/LICENSE_1_0.txt)
4-->
5
6Point-free style programming
7============================
8
9[Point-free style](https://en.wikipedia.org/wiki/Tacit_programming) programing(or tacit programming) is a style where the arguments to the function are not explicity defined. Rather, the function is defined as the composition of other functions where function adaptors manipulate the function arguments. The advantage of using point-free style in C++ is the template machinery involved with function arguments can be avoided.
10
11Variadic print
12--------------
13
14For example, if we want to write a variadic print function that prints each argument, like this:
15
16    print("Hello", "World");
17
18We would write something like the following, which would recursively iterate over the arguments using varidiac templates:
19
20    // Base case
21    void print()
22    {}
23
24    template<class T, class... Ts>
25    void print(const T& x, const Ts&... xs)
26    {
27        std::cout << x;
28        print(xs...);
29    }
30
31Instead with point-free style, we can write this using the [`proj`](/include/boost/hof/by) adaptor, which calls a function on each arguments. Of course, `std::cout` is not a function, but we can make it one by using `BOOST_HOF_LIFT`:
32
33    BOOST_HOF_STATIC_FUNCTION(simple_print) = BOOST_HOF_LIFT(std::ref(std::cout) << _);
34
35This uses the [placeholders](/include/boost/hof/placeholders) to create a function that prints to `std::cout`. Then we can pass `simple_print` to the [`proj`](/include/boost/hof/by) adaptor:
36
37    BOOST_HOF_STATIC_FUNCTION(print) = proj(simple_print);
38
39As the [`proj`](/include/boost/hof/by) adaptor calls the function for each argument passed in, `b(f)(x, y)` is the equivalent of calling `f(x)` and then `f(y)`. In this case, it will call `simple_print(x)` and then `simple_print(y)`:
40
41    print("Hello", "World");
42
43Which prints out:
44
45    HelloWorld
46
47Of course, this puts all the output together, but we can further extend this to print a new line for each item by composing it:
48
49    BOOST_HOF_STATIC_FUNCTION(print_lines) = proj(flow(simple_print, _ << std::integral_constant<char, '\n'>{}));
50
51The [flow](/include/boost/hof/flow) adaptor does function composition but the functions are called from left-to-right. That is `flow(f, g)(x)` is equivalent to `g(f(x))`. So in this case, it will call `simple_print` on the argument which returns `std::cout` and then pass that to the next function which calls the stream with the newline character. In the above, we write `std::integral_constant<char, '\n'>{}` instead of just `'\n'` because the function is statically defined, so all values must be defined statically.
52
53So now calling `print_lines`:
54
55    print_lines("Hello", "World");
56
57It will print out:
58
59    Hello
60    World
61
62With each argument on its own line.
63
64Variadic sum
65------------
66
67Another example, say we would like to write a varidiac version of `max`. We could implement it like this:
68
69    // Base case
70    template<class T>
71    T max(const T& x)
72    {
73        return x;
74    }
75
76    template<class T, class... Ts>
77    T max(const T& x, const T& y, const Ts&... xs)
78    {
79        return std::max(x, max(y, xs...));
80    }
81
82With point-free style programming, we can recognize this is a [fold](https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29), and write it using the [`fold`](/include/boost/hof/fold) adaptor, which will do a fold over the variadic parameters:
83
84    BOOST_HOF_STATIC_FUNCTION(max) = fold(BOOST_HOF_LIFT(std::max));
85
86[`BOOST_HOF_LIFT`](/include/boost/hof/lift) is used to grab the entire overload set of `std::max` function, which is needed since `std::max` is templated and we want the variadic `std::max` function to handle any types as well. So now it can be called like this:
87
88    auto n = max(1, 2, 4, 3); // Returns 4
89    auto m = max(0.1, 0.2, 0.5, 0.4); // Returns 0.5
90
91By using [`fold`](/include/boost/hof/fold), `max(1, 2, 4, 3)` will call `std::max` like `std::max(std::max(std::max(1, 2), 4), 3)` and `max(0.1, 0.2, 0.5, 0.4)` will be called like `std::max(std::max(std::max(0.1, 0.2), 0.5), 0.4)`.
92
93