---
title: "Function factorization with the `vfunc` package"
author: "Robin K. S. Hankin"
output: html_vignette
bibliography: vfunc.bib
link-citations: true
vignette: >
  %\VignetteIndexEntry{The vfunc package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(rmarkdown.html_vignette.check_title = FALSE)
library("vfunc")
set.seed(1)
```

```{r out.width='20%', out.extra='style="float:right; padding:10px"',echo=FALSE}
knitr::include_graphics(system.file("help/figures/vfunc.png", package = "vfunc"))
```

To cite the `vfunc` package in publications please use @rcore2024.

In mathematics, given two functions
$f,g\colon\mathbb{R}\longrightarrow\mathbb{R}$, it is natural to
define $f+g$ as the function that maps $x\in\mathbb{R}$ to $f(x) +
g(x)$.  However, in base R, objects of class `function` do not
have arithmetic methods defined, so idiom such as `f + g`
returns an error, even though it has a perfectly reasonable
expectation.  The `vfunc package` offers this functionality.
Other similar features are provided, which lead to compact and
readable idiom.  A wide class of coding bugs is eliminated.

# Introduction

Consider the following R session:
```{r error=TRUE}
f <- function(x){x^2}
g <- function(x){1/(1-x)}
f + g
```

Above, there is a reasonably clear expectation for `f + g`: it should
give a function that returns the sum of `f()` and `g()`; something
like `function(x){f(x) + g(x)}`.  However, it returns an error
because `f` and `g` are objects of `S4` class `function`, which do not
have an addition method.  Further, it is not possible to define
`Arith` group `S4` methods [in this case, overloading addition] so
that this idiom operates as desired.  This is because the `function`
class is _sealed_ in `S4`: the definition of new methods for it is
prohibited.  Here I present the `vfunc` R package that furnishes
appropriate idiom.  The package defines a new `S4` class `vf`
("virtual function") which inherits from `function`, but for which new
methods can be defined.  This device furnishes some ways to
apply `Arith` methods for functions.

# The package in use

The package is designed so that objects of class `vf` operate as
functions but are subject to arithmetic operations, which are executed
transparently.  For example:


```{r vfuncfplusg}
library("vfunc")
f <- as.vf(f)
g <- as.vf(g)
(f + g)(1:10)
```

Above, we coerce `f` and `g` to objects of `S4` class `vf` [for
"virtual function"].  Such objects have `Arith` methods defined and
may be combined arithmetically; for example addition is dispatched to

```
function(e1, e2){as.vf(function(...){e1(...) + e2(...)})}
```

The `vf` class has a single `.Data` slot of type `function` which
means that objects of this class inherit much of the behaviour of base
class `function`; above, we see that `e1` and `e2` may be executed
with their argument list directly.  In practice this means that `f+g`
behaves as intended, and suggests other ways in which it can be used:

```{r showfplusginvfunc}
(f + 4*g - f*g)(1:10)
```

The advantages of such idiom fall in to two main categories.  Firstly,
code can become considerably more compact; and secondly one can guard
against a wide class of hard-to-find bugs.  Now consider `f()` and
`g()` to be trivariate functions, each taking three arguments,
say,

```{r}
f <- function(x,y,z){x + x*y - x/z}
g <- function(x,y,z){x^2 - z}
```

and $x=1.2$, $y=1.7$, $z=4.3$.  Given this, we wish to calculate

$$(f(x,y,z) + g(x,y,z))(f(x,y,z) + 4 - 2f(x,y,z)g(x,y,z)).$$

How would one code up such an expression in R?  The standard way would be

```{r standardway}
 x <- 1.2
 y <- 1.7
 z <- 4.3		
(f(x,y,z) + g(x,y,z))*(f(x,y,z) + 4 - 2*f(x,y,z)*g(x,y,z))
```

Note the repeated specification of argument list `(x,y,z)`, repeated
here five times.  Now use the `vfunc` package:


```{r usevfunc}
f <- as.vf(f)
g <- as.vf(g)
((f + g)*(f + 4 - 2*f*g))(x,y,z)
```

See how the package allows one to ''factorize'' the argument list so
it appears once, leading to more compact code.  It is also arguably
less error-prone, as the following example illustrates.  Consider

$$
f(x+z,y+z,f(x,x,y)-g(x,x,y)) + g(x+z, y+z,f(x,x,y)-g(x,x,y))
$$


(such expressions arise in the study of dynamical systems).  Note that
functions $f$ and $g$ are to be evaluated with two distinct sets of
arguments at different levels of nesting, namely $(x,x,y)$ at the
inner level and $(x+z,y+z,f(x,x,y)-g(x,x,y)$ at the outer.  Standard R
idiom would be


```{r compexample}
f(x + z, y + z, f(x, x, y) - g(x, x, y)) + g(x + z, y + z, f(x, x, y) - g(x, x, y))
```

The author can attest that finding bugs in such expressions can be
difficult [it is easy to mistype `(x,x,y)` in one of its
occurrences, yet difficult to detect the error].  However, `vfunc`
idiom would be

```{r fgxzyz}
(f + g)(x + z, y + z, (f - g)(x, x, y))
```

which is certainly shorter, arguably neater and at least the author
finds such constructions considerably less error-prone.  In this form,
one can be sure that both `f()` and `g()` are called with
identical arguments at each of the two levels in the expression, as
the arguments appear only once.

## Overloading

Looking again at the method for `vf` addition, viz

```
function(e1, e2){as.vf(function(...){e1(...) + e2(...)})}
```

we see the `+` operator is used to sum the return values of `e1()` and
`e2()`.  There is no reason that this operator cannot itself be
overloaded, and the `vfunc` package works transparently if this is the
case, with either `S3` or `S4`.  Taking the `onion`
package [@hankin2006_onion] as an example:

```{r sprayexamp}
library("onion")
options("show_onions_compactly" = TRUE)
f <- as.vf(function(x,y){x + x*y})
g <- as.vf(function(x,y){x^2 + y})
(f + g - f*g)(1 + Hj,Hk)
```

## Primitive functions

The R language includes a number of primitive functions as `S4` Math
generics, including the trig functions such as `sin()`, and a few
others such as the cumulative sum `cumsum()`.  These functions are
quite deep-seated and cannot easily be modified to work with objects
of class `vf`.  The package defines capitalized versions of primitive
functions to operate with other objects of class `vf`.  Taking `sin()`
as an example we have

```{r showsin}
vfunc::Sin
```

Then we may, for example, combine trig functions with user-defined functions:

```{r combinetriganduser}
fun <- as.vf(function(x){x^2 + 2})
(fun(Sin) + Sin(fun) - 3*Sin*fun)(0.32)
```

Above, we see package idiom being used to evaluate $\sin^2(0.32) + 3 +
\sin(0.32^2+2) - 3\cdot\sin 0.32\cdot(0.32^2+2)$.  In base R:

```{r seeeval}
fun(sin(0.32)) + sin(fun(0.32)) - 3*sin(0.32)*fun(0.32)
```

This construction allows one to define composite functions such as

```{r defcomposite}
j <- as.vf(function(x,y){Cos(x) + Sin(x-y)})
k <- as.vf(function(x,y){Tan(x) + Log(x+y)})
l <- as.vf(function(x,y){Sin(x/2) + x^2   })
```

(note that functions `j()`, `k()` and `l()` are bivariate).  Then
compare

```{r looktwo1}
(j + k + l)(Sin + Log, Cos + Exp)(Sin + Tan)(0.4)
```

with the one-stage idiom which reads:


```{r looktwo2}
j(sin(sin(0.4) + tan(0.4)) + log(sin(0.4) + tan(0.4)), cos(sin(0.4) + tan(0.4)) +
exp(sin(0.4) + tan(0.4))) + k(sin(sin(0.4) + tan(0.4)) + log(sin(0.4) + tan(0.4)),
cos(sin(0.4) + tan(0.4)) + exp(sin(0.4) + tan(0.4)))+ l(sin(sin(0.4) + tan(0.4)) +
log(sin(0.4) + tan(0.4)), cos(sin(0.4) + tan(0.4)) + exp(sin(0.4) + tan(0.4)))
```

and the multi-stage idiom:

```{r looktwo3}
A <- function(x,y){j(x,y) + k(x,y) + l(x,y)}
B <- function(x){sin(x) + log(x)}
C <- function(x){cos(x) + exp(x)}
D <- function(x){sin(x) + tan(x)}
x <- 0.4
A(B(D(x)), C(D(x)))
```

See how the one-stage idiom is very long, and the multi-stage idiom is
opaque [and nevertheless has repeated instances of `(x,y)` and `x`].

# Conclusions

The `vfunc` package allows functions to be ''factorized'', that
is, `f(x) + g(x)` to be re-written `(f + g)(x)`.  This allows
for concise idiom and eliminates a certain class of coding errors.
The package also allows for recursive application of such ideas.



## References
