# FP in C++: Partial application

## Walletfox.com

### This function calculates area of a circular sector

```double secArea(double theta, double radius){
}
```

### We wil need nested lambda to express partial application

```auto papply = [](auto f, auto x) {
return [=](auto y){
return f(x,y);
};
};
```
`auto op = papply(f, 6.28);`

Outer lambda contains the argument known at the beginning, i.e. the specialized argument.

### Specialization becomes easy

To achieve specialization we only have to pass the function and its first argument.

```auto op = papply(secArea,2*M_PI); // full circle specialization
auto val = op(3.0); // area of a circle with radius 3.0
```

### In the previous case, specialization concerned the first function argument.

`double secArea(double rAngle, double radius);`

### pow C library function raises the base to its exponent

```double pow (double base, double exponent);
```

### Not what we intended

This application would produce 2 raised to any power.

```auto op = papply(pow,2); // 2 raised to any power
auto val = op(3); // 2^3 = 8
```

### The pow function requires specialization of the second argument.

```double pow (double base, double exponent);
```

### This problem can be solved via argument swap

1. with a general higher-order function
2. with a dedicated lambda expression
3. with std::bind and std::placeholders

### Swap arguments with a general nested lambda

```auto swapArgs = [] (auto f){
return [=](auto x, auto y){
return f(y,x);
};
};
```
```auto op = papply(swapArgs(pow), 2); // raises to the power of 2
auto val = op(3); // 3^2 = 9, what we intended
```
This solution only works for binary functions.

### Dedicated lambda works also for multi-argument problems

```auto powS = [](auto exponent, auto base){
return pow(base, exponent);
};
```
```auto op = papply(powS, 2); // raises to the power of 2
auto val = op(3); // 3^2 = 9, what we intended
```

### Dedicated solution can be expressed in a more compact form

```auto op = papply([](auto exponent, auto base){
return pow(base, exponent);}, 2);

auto val = op(3); // 3^2 = 9, what we intended
```

### Another option is to use the library function std::bind

This solution bypasses the use lambda expressions.

```auto op = std::bind(pow, std::placeholders::_1, 2);
auto val = op(3); // 3^2 = 9, what we intended
```

std::bind and std::placeholders require the header <functional>

### This is a general equation for radioactive decay

```double age(double remainingProportion, double halflife){
return log(remainingProportion)*halflife / -log(2);
}
```

### T1: Specialize the general equation for C14

Substitute half-life with the half-life of carbon C14, i.e. 5730 years. Mark all the correct answers.

### T2: Determine age

How old is a fossil that has 40% of C14 compared to a living sample?

Hint:
Use e.g. `auto val = op2(0.4);`

### Let's specialize std::regex_match

std::regex_match determines if a regular expression re matches the entire character sequence s.
```bool std::regex_match( const std::string& s,
const std::regex& re,
std::regex_constants::match_flag_type flags =
std::regex_constants::match_default);
```

We are going to ignore the third parameter since it has a default value.

### We use dedicated lambda to achieve the desired argument ordering

```auto op = papply([](auto re, auto str){
return std::regex_match(str, re);},
std::regex("(\\w+)(\\.|_)?(\\w*)@(\\w+)(\\.(\\w+))+"));
```
```auto val1 = op("test@walletfox.com") // return 1, i.e. true
auto val2 = op("test@walletfoxcom") // return 0, i.e. false
```

### This is a formula for final velocity of a moving object

```double velocity(double v0, double a, double t){
return v0 + a*t;
}
```

### We wil need nested lambda and parameter pack

```auto papply = [](auto f, auto... args) {
return [=](auto... rargs) {
return f(args..., rargs...);
};
};
```
The use of multiple arguments is expressed with a parameter pack ...

args refers to the primary specialization, rargs refers to the rest of the arguments.

### We apply it analogously to the binary case

```auto op = papply(velocity, 0.0, 9.81);
auto val = op(4.5); // returns 44.15 m/s
```
In this specific case, no swaps were necessary.

### This function performs left fold on a collection

```auto leftFold = [](auto col, auto op, auto init) {
return std::accumulate(std::begin(col), std::end(col),
init, op);
};
```
The function leftFold combines elements of the collection col, using a binary operation op, starting from the value init.

### This specialization of leftFold performs summation

```auto op = papply([](auto op, auto init, auto col){
return leftFold(col, op, init);},
std::plus<>(), 0.0);
```
The function computes the sum of elements of the collection starting from the value 0.0.

### T3: Specialize leftFold to compute product

Fill in the blanks to compute a product of a collection:
```auto op = papply([](auto op, auto init, auto col){
return leftFold(col, op, init);},
__________, ___);
```

### Let's sum it all up

Partial application
• produces functions that "remember" certain values
• can be expressed with the help of nested lambda
• might require argument reordering (general, dedicated or std::bind and std::placeholders)
• multiargument partial application requires a parameter pack